类级别变量是单例模式中的吗,当以异步方式访问时,是否会导致脏读取?

huangapple go评论90阅读模式
英文:

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 = &quot;test/v1.0/myputcall&quot;)
public class MyController {

    @Autowired
    MyServiceImpl myServiceImpl;

    @PutMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity&lt;String&gt; 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==&quot;prod&quot;){
            updateRequired=true;
        }

        if(updateRequired){
            tryUpdateWithRetry();
        }

private tryUpdateWithRetry(){
            for(;count&lt;3;retryCount++){
                //call some other app
                int status = UpdateUser.update(userId);
                if(status==0){
                    return;
                }
            }
        log.info(&quot;update attempted thrice, non zero return status.&quot;);
        }

    }

}    

答案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.

huangapple
  • 本文由 发表于 2020年9月23日 03:32:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/64016561.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定