我正在学习Java中的volatile和synchronized,我发现synchronized用于读取 - 修改 - 写入操作,如x++
,而volatile用于读写操作。我想问你2个问题。如何看待读写操作?
对于第二个问题,我有这个代码:
public class StopThread {
private static volatile boolean stop;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
while (!stop) {
System.out.println("In while...");
}
}
}).start();
TimeUnit.SECONDS.sleep(1);
stop = true;
}
}
我不明白为什么这是一个读写操作,因为stop变量将从false修改为true。那么这不是一个读 - 修改 - 写操作吗?谢谢!
声明stop = true;
不是“读写”操作,而只是写操作。它根本不读取变量的旧值。如果stop
以前的值是true
,那么该声明没有效果,没有注意到差异。
“读 - 修改 - 写”操作,也称为“读 - 更新 - 写”操作意味着一个操作,它读取前一个值,根据它计算一个新值,并将新值写回变量。当不使用特殊的原子更新构造时,此操作的问题在于,执行写入时,可能发生了并发更新,因此使用基于过时的先前值的计算值覆盖变量。
对于你的boolean
变量,“read-modify-write”操作可能看起来像
if(!stop) stop = true;
要么
stop = !stop;
但对于第一个变体,缺少并发更新不会产生太大影响,因为如果变量已经是true
,则该语句无效。如果同时执行,则第二个可能错过更新,因此,不反映正确数量的翻转操作,但是通常使用并发boolean
更新以进行多个单个状态转换是容易出错的。
“读写”操作,即其间没有“修改/更新”,将是一个读取旧值供以后使用并写入不基于旧值的新值的操作。喜欢
Type old = variable;
variable = newValue;
// use old here
当没有原子地完成时仍然会丢失更新。因此,这种操作还需要不止一个volative
变量。例如。 AtomicInteger.getAndSet
或VarHandle.getAndSet
。
所以扩展你的榜样
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public class StopThread {
private static volatile boolean stop;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
while(!stop) {
System.out.println("In while...");
}
}
}).start();
for(int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
boolean old = stop; // broken because
stop = true; // not atomic
System.out.println(old? "other thread was faster": "sent stop signal");
}
}).start();
}
}
}
多个线程可能认为他们发送了停止信号。
如果您修复代码
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
public class StopThread {
private static final AtomicBoolean stop = new AtomicBoolean();
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
while(!stop.get()) {
System.out.println("In while...");
}
}
}).start();
for(int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
boolean old = stop.getAndSet(true);
System.out.println(old? "other thread was faster": "sent stop signal");
}
}).start();
}
}
}
正好一个线程将负责发送停止信号。