美文网首页
深入并发系列学习-2-volatile关键字

深入并发系列学习-2-volatile关键字

作者: 辉_ace | 来源:发表于2020-07-15 22:01 被阅读0次

在并发编程中,volatile是一个很重要的存在。它可以理解为是一个轻量级的synchronized。在多线程开发中,线程之间修改变量默认是不可见的。

volatile特性

  • 能够保证多个线程对共享变量的可见性。即一个线程修改了某个共享变量的值,修改后的值对其他线程可见。
  • 禁止指令重排(有序性)。
  • volatile 只能保证对单次读/写的原子性。类似于i++ 这种操作不具有原子性。

基础使用

演示如下:

public class VolatileBase {

    private static boolean flag;

    private static class MyThread implements Runnable{

        @Override
        public void run() {
            while (!flag){
            }
            System.out.println("running");
        }
    }

    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(new MyThread());

        thread.start();
        //让子线程先执行
        TimeUnit.SECONDS.sleep(1);
        flag=true;

        TimeUnit.SECONDS.sleep(5);
        System.out.println("main is ended!");
    }
}

根据演示结果,可以看到,子线程会在while中无限循环,就算主线程将flag修改为true,子线程也是无法知道的。验证了线程间变量的不可见性。

此时如果要在多线程下,保证共享变量的可见性,就需要在共享变量前添加volatile关键字。那何为可见性呢? 也就是说当一个线程修改一个共享变量时,另外一个线程能读到被修改的值。演示效果如下:

public class VolatileBase {

    private static volatile boolean flag;

    private static class MyThread implements Runnable{

        @Override
        public void run() {
            while (!flag){
            }
            System.out.println("running");
        }
    }

    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(new MyThread());

        thread.start();
        TimeUnit.SECONDS.sleep(1);
        flag=true;

        TimeUnit.SECONDS.sleep(5);
        System.out.println("main is ended!");
    }
}

根据演示结果,当共享变量添加了volatile后,子线程可以感知到变量值的改变,实现了多线程下共享变量的可见性。

使用volatile是否能保证数据一致性

volatile的一个特性就是,当共享变量存在计算时,其是无法保证原子性的,具体演示如下:

public class SafeDemo {

    private volatile long count = 0;

    public long getCount() {
        return count;
    }

    public void setCount(long count) {
        this.count = count;
    }

    public void incrCount(){
        count++;
    }

    public static class MyThread implements Runnable{

        private SafeDemo safeDemo;

        public MyThread(SafeDemo safeDemo) {
            this.safeDemo = safeDemo;
        }

        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                safeDemo.incrCount();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {

        SafeDemo safeDemo = new SafeDemo();
        Thread thread1 = new Thread(new MyThread(safeDemo));
        Thread thread2 = new Thread(new MyThread(safeDemo));

        thread1.start();
        thread2.start();

        TimeUnit.SECONDS.sleep(1);

        System.out.println(safeDemo.count);
    }
}

根据演示可以看到,其并不能保证共享数据的一致性,volatile只保证可见性。

其他更深层次的内容,如指令重排、内存语义、写底层、读底层等,都需要理解JMM(Java内存模型),后续会有专门章节深入讲解。

相关文章

网友评论

      本文标题:深入并发系列学习-2-volatile关键字

      本文链接:https://www.haomeiwen.com/subject/spcshktx.html