假设这个类:
public class AmIThreadSafe {
private int a;
private int b;
AmIThreadSafe(int a, int b) {
this.a = a;
this.b = b;
}
}假设实例对该类的引用(声明为volatile)一旦this(引用)转义,某些线程(导致争用条件)即可访问:
volatile AmIThreadSafe instance = new AmIThreadSafe(1,2);在这里,我确信分配instance引用的事实发生在线程读取之前。
但是AmIThreadSafe's字段呢?
外部volatile关键字是否也意味着与a和b字段有关的happens-before关系?或者,是否有可能因为在构造函数期间可能出现语句重新排序而导致任何线程看到陈旧的值(在本例中是自int以来的默认值)?
换句话说,我应该声明a和b final或volatile,以防止在JMM中出现任何意外,还是仅仅在实例的引用上指示volatile?
下面的文章通过其示例证实,在我的示例中,a和b不受阻止永久a关系的JMM优化的保护。
http://jeremymanson.blogspot.fr/2008/11/what-volatile-means-in-java.html
发布于 2012-11-14 00:27:16
将instance声明为volatile并不表示它的字段为volatile,但是如果我正确理解了您的问题,那么-是的,在您的情况下就足够了。
每规范第17.4.5节
volatile写入-在其他线程中读取任何后续的volatile之前。因此,如果一个线程认为instance已经初始化,那么instance的初始化就在它之前发生,而instance字段的初始化发生在此之前,所以线程会认为instance的字段已经初始化了。
发布于 2012-11-14 00:11:21
,不,,这还不足以使它不稳定。但是,线程安全取决于使用。例如,如果另一个线程正在修改这些值,这仍然会产生意想不到的结果。
为简单起见,假设public变量
volatile AmIThreadSafe instance = new AmIThreadSafe(1,2);
if (instance.x == 0) {
// instance.x might have changed between checking and assigning
instance.x = instance.x + 1;
}volatile只适用于变量(例如,x和y并不会因为instance的存在而自动成为volatile )。这在JLS 8.3.1.4中应该是清楚的。
发布于 2012-11-14 00:14:01
在您的情况下,volatile只适用于AmlThreadSafe的引用。您仍然必须使实例变量(a和b)成为volatile,或者在synchronized块中访问它们。否则,您可能会得到陈旧的数据。
https://stackoverflow.com/questions/13371066
复制相似问题