Spring 竞争条件单例服务有状态或无状态

use*_*946 2 java spring multithreading spring-mvc race-condition

我有点担心使用 Spring 的竞争条件。我知道各种范围(单例、原型、会话等)之间的区别

我也知道:

  • 默认情况下,服务具有单例范围
  • 只要我的 bean 是无状态的,我就不会有竞争条件的问题

尽管我对这个无国籍的东西不是 100% 确定。在谈论状态时,我的研究来源总是只关注共享实例变量,但竞争条件不仅会在访问实例变量时出现。我创建了以下示例来说明我的问题:

@Service
public class AppleService {

  @Autowired
  private AppleRepository appleRepository;

  @Override
  public void doSomethingWithAppleCategory(String appleCategory) {
    boolean existsAppleInCategory = existsAppleInCategory(appleCategory);
    if(existsAppleInCategory) {
        // do something
    }
    else {
        throw new RuntimeException("There is no apple in the category: " + appleCategory);
    }
  }

  private boolean existsAppleInCategory(String appleCategory) {
    Iterable<Apple> allApples = appleRepository.findAll();
    return allApples.stream().anyMatch(a -> a.getAppleCategory().equals(appleCategory));
  } 
}
Run Code Online (Sandbox Code Playgroud)

您可以假设该服务用于休息控制器或类似的东西。根据我的理解,当调用方法 existsAppleInCategory 时,竞争条件可能会出现问题。例如,thread1 有它的插槽,并将“false”写入变量existsAppleInCategory。然后线程 2 将其插槽覆盖为“true”。之后线程 1 有另一个时隙。=> 线程 1 现在“做某事”而不是抛出 RuntimeException。

我的假设正确吗?在这种情况下,我有竞争条件问题吗?如果不是为什么?您能否推荐任何有关该主题的详细资料(在线资料、书籍等)?

先感谢您!

M. *_*num 5

假设这AppleRepository是一个无状态的单身人士,并在此省略了数据库(因为您的问题是关于java的)。

简而言之,线程 1 无法看到线程 2 中的变量,因此您没有任何并发​​问题。

每个正在执行的线程都有自己的堆栈,在该堆栈上有方法内部使用的变量等,因此线程 1 无法看到existsAppleInCategory来自线程 2 的变量,反之亦然。该变量是方法的局部变量(实际上是执行块),并且每个线程在堆栈上都有自己的副本。

如果existsAppleInCategory是实例级变量,则情况会有所不同,因为您共享了状态。在这种情况下,线程可能会看到彼此的数据(取决于写入/读取状态的时间以及volatile关键字的使用)。