java中的易失性标识符
我不明白我读到的那几句话: 因为访问易失性变量从不持有锁,所以它不是 适用于我们希望将读更新写作为原子的情况 操作(除非我们准备“错过更新”) 什么意思,我不能读写 什么时候我想使用volatile而不是简单的boolean。在C#中,我记得我可以使用一个简单的静态bool来控制线程的启动和停止,但在java中我需要使用标识符“volatile”:java中的易失性标识符,java,thread-safety,volatile,Java,Thread Safety,Volatile,我不明白我读到的那几句话: 因为访问易失性变量从不持有锁,所以它不是 适用于我们希望将读更新写作为原子的情况 操作(除非我们准备“错过更新”) 什么意思,我不能读写 什么时候我想使用volatile而不是简单的boolean。在C#中,我记得我可以使用一个简单的静态bool来控制线程的启动和停止,但在java中我需要使用标识符“volatile”: 这句话讲的是这个例子: public class CounterClass { private volatile int counter;
这句话讲的是这个例子:
public class CounterClass {
private volatile int counter;
public int increment() {
return counter++;
}
}
尽管计数器
具有volatile
修饰符,但不能保证如果两个线程访问increment()
方法,将返回两个不同的整数。因为计数器+++
操作不是原子操作。它是get、increment、return
。两个线程可能同时调用increment()
,第一个线程处于get
阶段,第二个线程处于get
阶段,然后第一个线程处于increment
阶段
概要:volatile
不保证原子性或其他任何东西。它只是保证当您访问变量时,不会收到旧的缓存值。但它不能保证任何线程安全性或原子性
我什么时候要使用volatile
FWIW Brian Goetz在中列出了使用volatile的五种模式:
> public class StoppableTask extends Thread {
private volatile boolean pleaseStop;
public void run() {
while (!pleaseStop) {
// do some stuff...
}
}
public void tellMeToStop() {
pleaseStop = true;
}
}
顺便说一句,这张图片帮助我计算了volatile:
上面,
ready
是不稳定的。请注意,无论有什么保证,这些保证仅用于赋值,不用于读更新写
- 上图取自杰里米·曼森的博客文章:。
“第一个线程写入
,它将成为通信的发送方。第二个线程读取ready并查看第一个线程写入的值。因此,它成为一个接收器。因为发生了此通信,所以线程1在写入ready之前看到的所有内存内容,在线程2读取ready的值true之后,都必须对线程2可见。”ready
volatile
(您不会再将其设置为false,对吧?)来获得“更容易/更安全/更理智”的信息用Java编写并发代码的工具,请查看Java.util.concurrent。它有线程管理类,还有一个AtomicBoolean。如果您查看该算法,它应该将其设置为true和false,并防止循环失败infinite@Thilo:不,您需要volatile
!没有它,就不能保证线程会看到设置为true
的标志。实际上,一些编译器优化甚至可以从循环中删除该条件,使其成为无端循环。@Thilo-如果在上述示例中不使用volatile
,则可以生成无限循环:)我明白了。因此,我们有更多的理由停止处理低级内容,使用java.util.concurrent。