英文:
Can class level variables in a singleton cause dirty reads when accessed in an async manner?
问题
如果通过标有 @RestController 注解的类调用标有 @Service 注解的类的异步方法,我们的服务类的全局变量会在线程之间共享吗?
我提出这个问题是因为我了解每个线程都会得到正在执行的类的本地副本,如果单例类中的共享全局变量不是 volatile,它是否仍会共享值或导致脏读或写入。
需要注意的是,这两个变量是基本数据类型,所以我认为它们将存储在堆栈上而不是堆上。
由于每个线程都会得到该类的副本,而变量是基本数据类型,因此每个线程在堆栈上本地更新,而不是在堆上。
@RestController
@RequestMapping(value = "test/v1.0/myputcall")
public class MyController {
@Autowired
MyServiceImpl myServiceImpl;
@PutMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> activate(@RequestBody UserDTO user) {
// Controller calls the async activate method in singleton service class.
myServiceImpl.activate(user.userType, user.userID);
}
}
@Service
public class SwitchServiceImpl {
private int retryCount = 0;
private boolean updateRequired = false;
@Async
public void activate(String userType, String userId){
if(userType.equals("prod")){
updateRequired = true;
}
if(updateRequired){
tryUpdateWithRetry();
}
}
private void tryUpdateWithRetry() {
for(; retryCount < 3; retryCount++){
// call some other app
int status = UpdateUser.update(userId);
if(status == 0){
return;
}
}
log.info("update attempted thrice, non zero return status.");
}
}
英文:
If an async method of an @Service annotated class is called via a class annotated as @RestController, will the global variables of our service class be shared between threads?
I ask this because I understand that each thread gets a local copy of the class its executing, and if the shared global variable in a singleton class is not volatile, will it still share values or cause dirty reads or writes.
Point to note is that these two variables are primitives, so I assume that they will be stored on the stack and not on the heap.
As each thread will get a copy of the class, as the variables are primitive, wont each get updated locally on the stack instead of the heap?
@RestController
@RequestMapping(value = "test/v1.0/myputcall")
public class MyController {
@Autowired
MyServiceImpl myServiceImpl;
@PutMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> activate(@RequestBody UserDTO user) {
//Controller calls the async activate method in singleton service class.
myServiceImpl.activate(user.userType, user.userID);
}
}
@Service
public class SwitchServiceImpl{
private int retryCount = 0;
private boolean updateRequired = false;
@Async
public void activate(String userType, String userId){
if(userType=="prod"){
updateRequired=true;
}
if(updateRequired){
tryUpdateWithRetry();
}
private tryUpdateWithRetry(){
for(;count<3;retryCount++){
//call some other app
int status = UpdateUser.update(userId);
if(status==0){
return;
}
}
log.info("update attempted thrice, non zero return status.");
}
}
}
答案1
得分: 4
服务将在线程之间共享,因此其成员变量也将共享。如果使用volatile关键字,这将强制线程从/写入主内存中的值,而不是缓存详见此处。然而,如果多个线程更新值,这并不能阻止脏读/写。
如果值不应在线程之间共享,可以使用ThreadLocal。每个线程将有一个独立的值副本。如果可能,还应该考虑在方法内部使用局部变量。
如果需要安全地在线程之间访问值,可以使用原子变量或使用synchronized关键字或锁详情。
英文:
The service will be shared between threads, so will be its member variables. If you use the volatile keyword, this will force the thread to read/write the value from/to the main memory instead of cache details here. However this is not preventing dirty read/write if several threads update the value.
If the value should not be shared at all between threads, you can use ThreadLocal. Each thread will have an independent copy of the value. You should also consider to use local variable inside the method if possible.
If you need to access the value between threads safely, you can use Atomic variables or use synchronized keyword or locks details.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论