春のシングルトン豆のスレッドセーフ問題

 
    Spring統合プロジェクトでは、アノテーションを使用してBeanを注入することがどこにでもあります。プロジェクト開発では、voliateキーワードで考慮されたSpringのシングルトンBeanのスレッドセーフ問題をここに要約します。

    SpringシングルトンBean(@Autowiredなどでアノテーションが付けられたBean)は、デフォルトではシングルトンです。Springには、Beanのスレッドセーフな制御戦略がありません。並行性のセキュリティの問題は、開発によって決定されます。ただし、スレッドセーフは、共有リソースの競合があるかどうかによって異なります。SpringのシングルトンBeanがスレッドセーフであるかどうかは、BeanがステートフルBeanであるかステートレスBeanであるかによって異なります。

 

ステートフルBeanとステートレスBeanとは何ですか?

  • ステートフルBean:データストレージ機能があります。例:Beanにはユーザー情報を格納するためのUserオブジェクトがあります。
  • ステートレスBean:データストレージ機能なし

 
以下はテストデモです。

(1)MainUser.java:

@Data
@Builder
public class MainUser {
    
    

    private String id;

    private String sex;

    private String userName;

}

(2)SysMainController .java

@RequestMapping("/main")
@Controller
public class SysMainController {
    
    

    @Autowired
    private SysMainService mainService;

    @RequestMapping(value = "/test")
    public void mainMethod() {
    
    

        // thread-1
        new Thread(() -> {
    
    
            MainUser user = MainUser.builder()
                    .id("1")
                    .sex("男")
                    .userName("张三")
                    .build();
            mainService.testBean(user);
        }).start();

        // thread-2
        new Thread(() -> {
    
    
            MainUser user = MainUser.builder()
                    .id("2")
                    .sex("女")
                    .userName("小芳")
                    .build();
            mainService.testBean(user);
        }).start();

    }

}

(3)SysMainServiceImpl.java

@Service
public class SysMainServiceImpl implements SysMainService {
    
    

	/** 基本类型变量亦可 */
    private MainUser user; // 非定义为static的变量

    @Override
    public void testBean(MainUser user) {
    
    
        this.user = user;
        print();
    }

    public void print() {
    
    
        try {
    
    
            Thread.sleep(2000);
            System.out.println("ThreadName: " + Thread.currentThread().getName() + ", user: " + user);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

    }

}

複数のテストの結果:

ThreadName: Thread-57, user: MainUser(id=2, sex=, userName=小芳)
ThreadName: Thread-58, user: MainUser(id=2, sex=, userName=小芳)

 
結論として:

  • 両方のスレッドは、print()メソッドに入るときに独自のプライベートVMを作成しますが、ユーザーオブジェクトは共有されているため、開発では無視されがちです。
  • したがって、Bean of Springのシングルトンモードでは、データストレージ関数を持つオブジェクト/基本型変数/静的変数をグローバルレベルで定義しないでください。これにより、スレッドセーフの問題が発生します。そうすることで、BeanのScope = 'を宣言できます。プロトタイプ」またはローカル変数ThreadLocalを使用して定義する

 
上記は作者が遭遇した問題の思考実験です。間違った場所があれば指摘してください~~~

おすすめ

転載: blog.csdn.net/vipshop_fin_dev/article/details/109017732