【问题标题】:Thread safety in Spring Boot with Instance variables [duplicate]Spring Boot中的线程安全与实例变量[重复]
【发布时间】:2021-06-19 15:03:26
【问题描述】:

使用 Spring Boot 时方法(不使用类变量)是否线程安全? 我遇到了他们提到实例变量并不总是安全的龋齿链接?

我的疑问是如何创建竞争条件?下面的代码是线程安全的吗?如果是,那么我怎样才能使它成为线程 - 不使用类变量的不安全

 @RestController
        public class GreetingController {
        
            @Autowired
            private GreetingService greetingService;
        
            @GetMapping("/hello")
            public void greeting(@RequestBody MyUser myUser) throws Exception  {
                greetingService.getData(myUser);
             }  

 @Service
    public class GreetingService {
        
        @Autowired
        private DBService dBService;
        
        public void getData (MyUser m ) throws InterruptedException
        {
            
            dBService.getData(m);
        }




@Repository
         public class DBService {
    
        
           public MyUser getData(MyUser myUser) throws InterruptedException {
            
            System.out.println( "message  before: "  + myUser.getA() + " Thread : " +Thread.currentThread().getName());
    
            
            Thread.sleep(18000);
            System.out.println( "message after "  + myUser.getA() + " Thread : " +Thread.currentThread().getName());
            
            return myUser;
            
            
        }

【问题讨论】:

    标签: java spring multithreading spring-boot


    【解决方案1】:

    在简历中:是的,显然,这段代码是线程安全的。由于您使用的是 Servlet,因此每个请求都将在 servlet 容器提供的不同线程中提供服务(如果您使用 Spring Boot 的默认配置,则 servlet 容器是嵌入式 Tomcat)。

    为什么?因为只有在类作用域中声明的对象实例也是线程安全的(即GreetingService必须是线程安全的)时,此代码才是线程安全的

    举个例子:

    在第一个请求中执行的Thread#sleep 对后续请求没有影响(即其他请求将不会被阻止),因为后续请求在不同的线程上提供服务,如上所述。

    只要在请求生命周期内不为全局变量分配新值,就可以了。

    【讨论】:

    • @Matheus。感谢您的解释。所以除非我使用类变量并改变它的状态。我很好。这就是我所理解的。
    • 正确。不要管理在多个线程之间共享的 Singleton bean 的状态,尤其是在 Web 环境中。这可能会导致问题,然后变得线程不安全
    • 最后一个疑问。如果我想在不同线程之间共享状态,推荐的方法是什么?尤其是在 Spring 中
    • 我认为确保一次只允许一个线程更改对象(通过使用synchronized 关键字)是一种很好的方法。我从来不需要在线程之间共享状态,所以也许我不是回答这个问题的最佳人选。
    【解决方案2】:

    默认情况下(请参阅Does spring dependency injection create singleton objects?),通过 spring 依赖注入(在您的情况下为 @Autowired)注入的对象是单例。

    在您的示例中,控制器、服务和存储库各有一个实例。所以,本质上不是线程安全的。

    这些类的通常模式如您所见 - 仅对本身是线程安全的对象的实例使用类级变量。

    除非您希望共享数据(这种情况很少见),否则不要在类级变量中保留任何状态,并且您的代码将是线程安全的。

    如果您确实有意共享状态,请确保您注意使对该状态的访问是线程安全的。

    【讨论】:

    • 谢谢。但是我的代码在线程之上是否安全?如果不是如何?
    • 对我来说,所有这些看起来都是线程安全的,除了你的 DBService,我猜这不是你真正的代码。如果这是一个“普通”的数据库服务,它使用 JDBC 连接池访问数据库并返回结果(不改变任何实例变量),那肯定也是线程安全的。
    猜你喜欢
    • 2018-01-13
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 2014-09-20
    • 1970-01-01
    相关资源
    最近更新 更多