Spring 秒表并发

Spring StopWatch concurrency

我有一个 Bean 配置如下:

    @Bean(name = "myStopWatch")
    @Scope(value = "prototype")
    public MyStopWatch myStopWatch() {
       return new MyStopWatch();
    }

MyStopWatch class如下:

import org.springframework.util.StopWatch;

public class MyStopWatch {

   private StopWatch sw = new StopWatch();

   public void start() {
       if(!sw.isRunning()) {
           sw.start();
       }
   }

   public void stop() {
       if(sw.isRunning()) {
           sw.stop();
       }
   }
}

我们在高度并发的环境中使用这个 bean。如果我的理解是正确的,MyStopWatch class 不应该在线程之间共享,对吗?

但是,我们有时(很少)会收到以下错误:

java.lang.IllegalStateException: Can't start StopWatch: it's already running at org.springframework.util.StopWatch.start(StopWatch.java:127) at org.springframework.util.StopWatch.start(StopWatch.java:116)

到目前为止,我们无法通过测试重现此行为。我正在寻找有关如何正确定义 sw 变量(或 ma bean)以避免此错误的更多信息。

你的假设是错误的。将 bean 声明为 prototype 并不能确保线程安全。请参阅 this answer 了解更多详情。

就使用 Spring 的 StopWatch 而言,the documentation 指出它并非设计为线程安全的,也不打算在生产中使用。

首先,它不是线程安全的,文档中是这样说的。将你的 bean 作为 prototype 并不意味着不能有多个线程同时更新它,它只是意味着当你请求这样一个 bean 时 - 一直返回一个新实例(当使用 getBean@Autowired 例如)。

如果您想测量经过的时间(做某事花费了多少时间),请远离 Spring 中的 StopWatch。如果你有番石榴,它也有一个 StopWatch - 使用它(它仍然不是线程安全的),否则在你想要分析的代码的每个部分中一个简单的 System.nanoTime 就足够了。