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を使用して定義する
上記は作者が遭遇した問題の思考実験です。間違った場所があれば指摘してください~~~