java中的易失性标识符

java中的易失性标识符,java,thread-safety,volatile,Java,Thread Safety,Volatile,我不明白我读到的那几句话: 因为访问易失性变量从不持有锁,所以它不是 适用于我们希望将读更新写作为原子的情况 操作(除非我们准备“错过更新”) 什么意思,我不能读写 什么时候我想使用volatile而不是简单的boolean。在C#中,我记得我可以使用一个简单的静态bool来控制线程的启动和停止,但在java中我需要使用标识符“volatile”: 这句话讲的是这个例子: public class CounterClass { private volatile int counter;

我不明白我读到的那几句话:

因为访问易失性变量从不持有锁,所以它不是 适用于我们希望将读更新写作为原子的情况 操作(除非我们准备“错过更新”)

什么意思,我不能读写

什么时候我想使用volatile而不是简单的boolean。在C#中,我记得我可以使用一个简单的静态bool来控制线程的启动和停止,但在java中我需要使用标识符“volatile”:


这句话讲的是这个例子:

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;
  }
}
  • 状态标志(“规范”)
  • 一次性安全出版
  • 独立观察(“先前观察的延伸”)
  • “易失性bean”模式
  • 廉价的读写锁定技巧(“如果读取的数量远远超过修改的数量”)

  • 顺便说一句,这张图片帮助我计算了volatile:

    上面,
    ready
    是不稳定的。请注意,无论有什么保证,这些保证仅用于赋值,不用于读更新写

    • 上图取自杰里米·曼森的博客文章:。 “第一个线程写入
      ready
      ,它将成为通信的发送方。第二个线程读取ready并查看第一个线程写入的值。因此,它成为一个接收器。因为发生了此通信,所以线程1在写入ready之前看到的所有内存内容,在线程2读取ready的值true之后,都必须对线程2可见。”


    如果您不介意错过更新并运行一两次“太多”的迭代,那么您就不需要
    volatile
    (您不会再将其设置为false,对吧?)来获得“更容易/更安全/更理智”的信息用Java编写并发代码的工具,请查看Java.util.concurrent。它有线程管理类,还有一个AtomicBoolean。如果您查看该算法,它应该将其设置为true和false,并防止循环失败infinite@Thilo:不,您需要
    volatile
    !没有它,就不能保证线程会看到设置为
    true
    的标志。实际上,一些编译器优化甚至可以从循环中删除该条件,使其成为无端循环。@Thilo-如果在上述示例中不使用
    volatile
    ,则可以生成无限循环:)我明白了。因此,我们有更多的理由停止处理低级内容,使用java.util.concurrent。