java - 多线程环境下Spring Service实例变量

标签 java spring multithreading spring-mvc thread-safety

我最近遇到了竞争条件问题,因为在默认作用域(单例作用域)服务类中声明了实例变量。实例变量的目的是使我的代码更具可读性,并避免将同一变量不断传递给 Service 类中的不同私有(private)方法。例子如下:

@Service
public class SomeServiceImpl implements SomeService {
    private final StatusRepository statusRepository;
    private Predicate<Status> statusPredicate;

    @Autowired
    public SomeServiceImpl(StatusRepository statusRepository) {
        this.statusRepository = statusRepository;
    }

    @Override
    public List<Status> getAllowedStatuses(String userId) {
        statuses = statusRepository.getAll();
        initPredicate();
        appendPredicateA();
        appendPredicateB();
        List<Status> results = statuses.stream()
            .filter(statusPredicate)
            .collect(Collectors.toList());
        return results;
    }

    private void initPredicate() {
        statusPredicate = p -> p.getDefault().equals("default");
    }

    private void appendPredicateA() {
        statusPredicate.and(p -> p.getA().equals("A"));
    }

    private void appendPredicateB() {
        statusPredicate.and(p -> p.getB().equals("B"));
    }
}

这是我想要实现的目标的一个非常简单的示例。这显然不是线程安全的,因为现在服务类是有状态的。我可以简单地通过将 statusPredicate 变量转换为局部变量来解决此问题,并让 void 方法在附加新条件后返回谓词,但这会变得像这样困惑:

@Override
public List<Status> getAllowedStatuses(String userId) {
    statuses = statusRepository.getAll();
    Predicate<Status> statusPredicate = p -> p.getDefault().equals("default");
    statusPredicate = appendPredicateA(statusPredicate);
    statusPredicate = appendPredicateB(statusPredicate);
    List<Status> results = statuses.stream()
        .filter(statusPredicate)
        .collect(Collectors.toList());
    return results;
}

它会不断调用来修改变量并返回变量。

我知道一些可以解决此问题的解决方案,例如在 Service 类上添加 @RequestScope 以确保来自 HTTP 的每个请求都会获得该服务的新实例 服务对象,或在 Predicate 变量上使用 ThreadLocal。但是,我不太确定什么是最好的方法,以及是否可以开始在 Service 类中声明实例变量。如果一开始就让 Service 类有状态是不好的,那么我应该如何构建我的代码以使其更干净并仍然保持无状态?

请多多指教!提前致谢:D

最佳答案

Spring 服务可以是有状态的,这就是作用域的原因。

Spring Service 的默认范围是 Singleton,因为这是最广泛的用例。但您不应该使用可变的局部变量。

简单地说,只有在类实例化速度很快的情况下,尝试无状态设计并使用作用域来解决问题,否则 TreadLocal 的性能会更好。

关于java - 多线程环境下Spring Service实例变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52824586/

相关文章:

java - 查找父 Node 的属性并获取子 Node 属性的值

java - hibernate 主键的原语或包装器

java - 下载 Gradle 时 Ionic 构建 Android 错误

spring - Grafana 使用 http_server_requests_seconds_count 绘制每分钟 HTTP 请求数

php - php 中是否有类似 Java 的线程概念?

java - 如何动态增加jtable中Textarea的高度

spring - 使用Spring框架的AspectJ需要哪些jar?

c++ - WinAPI 将 "Edit"对话框写入管道(错误 : Stack around variable 'x' was corrupted)

java - 使用异步方法从 java 类更新 UI

java - Spring Tool Suite 向导生成的 NoClassDefFoundError