这是一堂课:
@NotThreadSafe
public class MutableInteger {
private int value;
public int get() { return value;}
public void set(int value) { this.value = value;}
}下面是我提出的后置条件:get()返回的值等于set()或0设置的值。
很容易看出,上述后置条件并不总是正确的。以两个线程A和B为例。假设A将value设置为5,B将其设置为8。在线程A中执行get()将返回8。它应该返回5。这是一个简单的竞赛条件。
如何使这个类线程安全?在实际使用的Java:一书中,作者对同一个对象上的value和这两个方法进行了保护。我不明白这对比赛有什么帮助。首先,set()不是一个复合动作。那么,为什么我们需要同步它呢?即使在那之后,种族状况也不会消失。一旦线程退出set()方法,锁就会被释放,另一个线程就可以启动锁并设置一个新的值。在初始线程中执行get()将返回新值,从而破坏后置条件。
(据我所知,作者正在保护get())以获取可见性信息。但我不知道如何消除比赛的条件。
发布于 2018-12-13 20:41:26
首先,set()不是复合动作。那么,为什么我们需要同步它呢?
您不是单独同步set(),而是根据同一个对象同步get()和set()方法(假设使这两个方法同步)。
如果您没有这样做,并且value变量没有标记为易失性,那么您就不能保证线程会因为每个线程缓存而看到正确的值。(线程a可以将其更新为5,那么即使在线程a更新了线程a之后,线程a仍有可能看到8。这就是在这个上下文中缺乏线程安全性的含义。)
所有的引用赋值都是原子的,这是正确的,所以在这个场景中不需要担心错误的引用。
即使在那之后,种族状况也不会消失。一旦线程退出set()方法,锁就会被释放,另一个线程就可以对锁进行补充,并设置一个新的值。
新线程设置新值(或新代码设置新值)在线程安全性方面根本不是问题--这是设计的,也是预期的。问题是如果结果是不一致的,或者特别是如果多个线程能够以不一致的状态并发地查看对象。
https://stackoverflow.com/questions/53769141
复制相似问题