说明volatile:这段代码是线程安全的吗?

JB *_*zet 3 java multithreading volatile

我试图说明volatile一个例子的用法和重要性,如果volatile省略的话,这个例子真的不会给出好的结果.

但我并不习惯使用volatile.如果volatile省略,则以下代码的想法是导致无限循环,并且如果volatile存在则完全是线程安全的.以下代码是否是线程安全的?你有没有其他现实和简短的代码示例使用volatile,如果没有它会给出明显不正确的结果吗?

这是代码:

public class VolatileTest implements Runnable {

    private int count;
    private volatile boolean stopped;

    @Override
    public void run() {
        while (!stopped) {
            count++;
        }
        System.out.println("Count 1 = " + count);
    }

    public void stopCounting() {
        stopped = true;
    }

    public int getCount() {
        if (!stopped) {
            throw new IllegalStateException("not stopped yet.");
        }
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        VolatileTest vt = new VolatileTest();
        Thread t = new Thread(vt);
        t.start();
        Thread.sleep(1000L);
        vt.stopCounting();
        System.out.println("Count 2 = " + vt.getCount());
    }
}
Run Code Online (Sandbox Code Playgroud)

irr*_*ble 10

Victor是对的,您的代码存在问题:原子性和可见性.

这是我的版本:

    private int count;
    private volatile boolean stop;
    private volatile boolean stopped;

    @Override
    public void run() {
        while (!stop) {
            count++; // the work
        }
        stopped = true;
        System.out.println("Count 1 = " + count);
    }

    public void stopCounting() {
        stop = true;
        while(!stopped)
           ; //busy wait; ok in this example
    }

    public int getCount() {
        if (!stopped) {
            throw new IllegalStateException("not stopped yet.");
        }
        return count;
    }

}
Run Code Online (Sandbox Code Playgroud)

如果线程观察到这一点stopped==true,则可以保证工作完成并且结果可见.

从易失性写入到易失性读取(在同一变量上)之间存在一个先发生的关系,因此如果有两个线程

   thread 1              thread 2

   action A
       |
 volatile write  
                  \
                     volatile read
                          |  
                       action B
Run Code Online (Sandbox Code Playgroud)

行动A发生在行动B之前; B中可以看到A中的写入

  • 原样,这个例子被打破了,因为`count ++`不是原子操作.您必须获取围绕该操作的锁定,或使用非阻塞的"AtomicInteger". (4认同)