Ada*_*ski 53 java concurrency multithreading volatile
我偶尔会使用一个volatile实例变量,在这种情况下,我有两个线程读取/写入它并且不希望获得锁定的开销(或潜在的死锁风险); 例如,计时器线程定期更新在某些类上作为getter公开的int ID:
public class MyClass {
private volatile int id;
public MyClass() {
ScheduledExecutorService execService = Executors.newScheduledThreadPool(1);
execService.scheduleAtFixedRate(new Runnable() {
public void run() {
++id;
}
}, 0L, 30L, TimeUnit.SECONDS);
}
public int getId() {
return id;
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题:鉴于JLS只能保证32位读取将是原子有任何一点曾经使用挥发性长时间?(即64位).
警告:请不要回复说使用volatile结束synchronized是预优化的情况; 我很清楚如何/何时使用,synchronized但有些情况volatile更可取.例如,在定义用于单线程应用程序的Spring bean时,我倾向于使用volatile实例变量,因为无法保证Spring上下文将初始化主线程中的每个bean的属性.
aio*_*obe 123
不确定我是否正确理解了您的问题,但是JLS 8.3.1.4.volatile字段:
字段可以声明为volatile,在这种情况下,Java内存模型可确保所有线程都看到变量的一致值(第17.4节).
并且,或许更重要的是,JLS 17.7双原子和非原子的非原子化处理:
17.7非原子性处理double和long
[...]
对于Java编程语言存储器模型的目的,对非易失性long或double值的单次写入被视为两个单独的写入:每个32位一个写入半.这可能导致线程从一次写入看到64位值的前32位,而从另一次写入看到第二次32位的情况.volatile和long值的写入和读取始终是原子的.对引用的写入和读取始终是原子的,无论它们是实现为32位还是64位值.
也就是说,"整个"变量由volatile修饰符保护,而不仅仅是两个部分.这诱使我声称使用volatile 比s 更重要,因为即使读取对于非易失性longs/double 也不是原子的.longint
这可以通过示例来证明
码
public class VolatileTest {
private long foo;
private volatile long bar;
private static final long A = 0xffffffffffffffffl;
private static final long B = 0;
private int clock;
public VolatileTest() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
foo = clock % 2 == 0 ? A : B;
bar = clock % 2 == 0 ? A : B;
clock++;
}
}
}).start();
while (true) {
long fooRead = foo;
if (fooRead != A && fooRead != B) {
System.err.println("foo incomplete write " + Long.toHexString(fooRead));
}
long barRead = bar;
if (barRead != A && barRead != B) {
System.err.println("bar incomplete write " + Long.toHexString(barRead));
}
}
}
public static void main(String[] args) {
new VolatileTest();
}
}
Run Code Online (Sandbox Code Playgroud)
产量
foo incomplete write ffffffff00000000
foo incomplete write ffffffff00000000
foo incomplete write ffffffff
foo incomplete write ffffffff00000000
Run Code Online (Sandbox Code Playgroud)
请注意,这只适用于在32位虚拟机上运行时,在64位虚拟机上我几分钟内无法获得单个错误.
小智 6
“volatile”有多种用途:
while (l != 0) {}.还有更多吗?