考虑一下Java并发的代码片段-
@ThreadSafe
public class SynchronizedInteger{
@GuardedBy("this") private int value;
public synchronized int getValue() {
return value;
}
public synchronized void setValue(int value) {
this.value = value;
}
}同一本书的摘录-
考虑易失性变量的一种好方法是设想它们的行为大致类似于上面清单中的SynchronizedInteger类,用要获取和设置的调用替换对易失性变量的读和写。但是访问易失性变量不会执行锁定,因此不会导致执行线程阻塞,从而使易失性变量成为比同步更轻的同步机制。
线程受限的特殊情况适用于易失性变量。对共享的易失性变量执行读-修改-写操作是安全的,只要您确保易失性变量仅从单个线程.写入。
因此,如果您将上述类中的实例变量设为易失性,然后删除同步关键字,则在此之后假设有3个线程。
线程A和线程B写入相同的易失性变量。
线程C读取易失性变量。
既然挥发性变量现在是从2个线程写入的,那么为什么对这个共享的易失性变量执行读-修改-写入操作是不安全的呢?
发布于 2016-08-05 16:39:51
关键字volatile用于确保其他Thread将看到对Object的更改。这并不强制,在操作完成之前,将在Object上执行非原子操作而不受其他Thread干扰。要执行此操作,您需要关键字synchronized。
发布于 2016-08-05 16:39:03
这是因为对易失变量的读-修改-写操作不是原子操作。v++实际上类似于:
r1 = v;
r2 = r1 + 1;
v = r2;因此,如果有两个线程执行该操作一次,则可能导致变量只增加一次,因为它们都读取旧值。这就是为什么它不安全的一个例子。
在您的示例中,如果移除同步,使字段易失性,并在基于返回setValue的条件逻辑之后有两个线程调用getValue --该值可能已被另一个线程修改,这将是不安全的。
如果需要原子操作,请查看java.util.concurrent.atomic包。
发布于 2016-08-05 17:14:52
如果您在不使用任何同步结构的情况下从多个线程中写入易失性变量,则必然会得到数据不一致错误。
在单个写入线程和多个读取线程的情况下,使用不同步的易失变量进行原子操作。
请确保从主内存而不是线程缓存中获取变量值。在一次写入和多次读取操作的情况下使用是安全的。
使用原子变量或同步或锁API从多个线程更新和读取变量。
请参阅有关的SE问题:
https://stackoverflow.com/questions/38793660
复制相似问题