在Java Concurrency in Practice一书中,您可以找到以下代码:
@ThreadSafe
public class SafePoint {
@GuardedBy("this") private int x, y;
private SafePoint(int[] a) { this(a[0], a[1]); }
public SafePoint(SafePoint p) { this(p.get()); }
public SafePoint(int x, int y) {
this.x = x;
this.y = y;
}
public synchronized int[] get() { return new int[] { x, y };
}
public synchronized void set(int x, int y) { this.x = x;
this.y = y;
}
}
标记为@ThreadSafe
。
我很确定这个类不是线程安全的(如果我理解这个术语的话)。
示例:
SafePoint racePublishedSafePoint; // field
// thread 1:
racePublishedSafePoint = new SafePoint(1,1);
// thread 2:
SafePoint sp;
while(true){
SafePoint sp = racePublishedSafePoint;
if(sp != null) break;
}
System.out.println(sp.get()[0]);
System.out.println(sp.get()[1]);
我相信有几种可能的结果:
我是对的吗?
如果为true,为什么作者将该类标记为线程安全?我认为这个线程安全的类 - 可以在没有复杂分析的情况下在并发应用程序中使用。
作者想说什么?
我已经读过了 Private constructor to avoid race condition
......我的主题不重复。
答案 0 :(得分:6)
我同意OP,该示例似乎违反了对@ThreadSafe
保证的通常理解。不安全的出版物比赛是非常真实的,当然,通过比赛发布SafePoint
时,您可以看到令人费解的行为。一些现实生活中的线程安全类可以在有趣的出版物中存活(String
是一个臭名昭着的例子),加剧了这种混乱。
就JCIP叙述而言,我没有纸质或电子副本,所以请与Doug Lea(主要作者之一)联系,他说:
我认为混淆的部分在JCIP文本中。我不认为
@ThreadSafe
涵盖出版比赛,或任何其他可能的比赛 在施工期间遇到。出版物安全得到处理 分开。不过,我可以看到别人怎么想。它是其中之一 我们探索的原因总是放置释放围栏 构造
Doug在谈论的最后一部分在"All Fields Are Final"中进行了简要描述,包括动机,实验补丁和绩效评估。