春单豆线安全

pcww981p  于 2022-10-04  发布在  Spring
关注(0)|答案(3)|浏览(78)

我是Spring的新手,有一些基本的问题。在下面给出的一个Spring示例中,我注意到EmployeeManager是自动连接的。

问题:

1.没有给出EmployeeManager作用域,所以我假设默认作用域是Singleton,而SpringBean不是线程安全的。这一假设是正确的吗?
1.EmployeeManager定义为Servlet的一部分,可由多个线程访问。假设“Delete”方法被多个线程同时调用,值为“1”、“2”和“3”,并且为每个线程生成相同的EmployeeManager示例(因为它是单例的),将执行哪个Delete值。Spring如何处理这种情况?

@Controller        
public class EditEmployeeController
{
@Autowired
private EmployeeManager employeeManager;

@RequestMapping(value = "/", method = RequestMethod.GET)
public String listEmployees(ModelMap map)
{
    map.addAttribute("employee", new EmployeeEntity());
    map.addAttribute("employeeList", employeeManager.getAllEmployees());
    return "editEmployeeList";
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String addEmployee(@ModelAttribute(value="employee") EmployeeEntity employee, BindingResult result)
{
    employeeManager.addEmployee(employee);
    return "redirect:/";
}
@RequestMapping("/delete/{employeeId}")
public String deleteEmplyee(@PathVariable("employeeId") Integer employeeId)
{
    employeeManager.deleteEmployee(employeeId);
    return "redirect:/";
}
public void setEmployeeManager(EmployeeManager employeeManager) {
    this.employeeManager = employeeManager;
}
}

员工经理-

public interface EmployeeManager {
    public void addEmployee(EmployeeEntity employee);
    public List<EmployeeEntity> getAllEmployees();
    public void deleteEmployee(Integer employeeId);
}

@Service
public class EmployeeManagerImpl implements EmployeeManager
{
    @Autowired
    private EmployeeDAO employeeDAO;
    @Override
    @Transactional
    public void addEmployee(EmployeeEntity employee) {
        employeeDAO.addEmployee(employee);
    }
    @Override
    @Transactional
    public List<EmployeeEntity> getAllEmployees() {
        return employeeDAO.getAllEmployees();
    }
    @Override
    @Transactional
    public void deleteEmployee(Integer employeeId) {
        employeeDAO.deleteEmployee(employeeId);
    }
    public void setEmployeeDAO(EmployeeDAO employeeDAO) {
        this.employeeDAO = employeeDAO;
    }
}
cnjp1d6j

cnjp1d6j1#

我同意上面的回答。我只想强调一点,避免争用条件的唯一方法是“@Transaction”位,这意味着Spring用一个在每个方法开始/结束时咨询TransactionManager的示例替换您的EmployeeManagerImpl。粗略地说:

public void addEmployee(EmployeeEntity employee) {
    transactionManager.startTransaction();
    employeeDAO.addEmployee(employee);
    transactionManager.endTransaction();
    // Just a rough outline; more accurately there should be 'finally' and rollback
}
...

现在,如果两个线程同时访问数据,它们的行为取决于您的TransactoinManager、事务隔离级别以及您的数据源与其交互的方式。在简单的情况下,您的线程将被迫等待;在其他情况下,数据库可以容忍一些并发访问。这种魔力归根结底是交易,而不是Spring。此外,在线程到达事务之前,也没有对它们的控制。如果3个不同的线程请求删除1、2和3,你不知道哪个线程会首先到达“startTransaction”。但这不应该真的有什么关系--你不妨遇到这样一种情况:周日有人要求删除“2”,周一有人要求删除“3”,周二有人要求删除“1”。你只需要一个合理一致的最终结果。

0qx6xfy6

0qx6xfy62#

Spring作用域单例与线程安全无关,这是两个不同的概念。

singletonprototype Bean的区别在于我们如何要求管理Bean生命周期的Spring容器返回Bean:

  • Singleton:确保每次调用Bean时都返回相同的示例。
  • Prototype:调用时返回新示例。

调用Bean可以由@autowirdeAppContext.getBean("beanName")触发

总而言之,这完全取决于注入Bean的对象,如果它不是线程安全的,那么显然它就不是线程安全的。

要了解更多信息,请参阅Spring Bean Scopes

yws3nbqq

yws3nbqq3#

1.是的,您的假设是正确的:如果您没有在Spring中为您的Bean声明一个作用域,那么它是一个Singleton by default,这意味着它不是线程安全的。
1.由于上面的假设是正确的,对您的问题的简短回答是,Spring不做任何处理单例Bean的多线程的事情,而是由您来处理该Bean的线程安全和并发性问题。好消息是,基于EmployeeManager Bean的功能和您概述的“1、2、3”场景,它实际上并不重要,您实际上不需要做任何事情。

对于为什么会出现这种情况,以下是一个长长的答案。与常见的误解相反,并不存在真正同时执行多个线程的情况。当然,它们可能看起来是同时执行的,但在幕后真正发生的是,JVM获取其中一个线程,执行其中的一部分,然后以最有效的方式(您会希望)开始在另一个线程上工作,然后是另一个线程,然后可能是第一个线程,等等。

这对您来说无关紧要的原因是,您的Bean没有任何状态。换句话说,您只是传递客户ID,并不关心哪个首先被删除。

现在,如果您实际上是在这些线程中传递相同的Customer对象,那么您可能会遇到问题。底线是,一般的经验法则是任何没有状态的Bean都可以是单例的。您可以阅读this article关于Spring Singletons和线程安全性的说明,以及更详细的内容。

希望这能帮上忙。

相关问题