美文网首页
Volatile,你想知道的这里都有

Volatile,你想知道的这里都有

作者: TUCJVXCB | 来源:发表于2019-08-07 23:15 被阅读0次

volatile关键字,是Java面试中避免不了的一个问题,我们来好好的剖析一下这个JUC的关键字。


volatile 是Java提供的一个轻量级同步机制。它保证了内存的可见性,不保证原子性,禁止指令重排序。我们用实际代码来分析这三个方面,分析完之后你就知道了为什么volatile是一个轻量级的同步机制了。

  • 可见性
    由JMM内存模型可以知道,线程拥有自己的工作内存,该工作内存由自己独享,其他线程访问不了。线程在进行读写操作时,要从主内存中拷贝一份数据放入自己的工作内存中,然后在自己的工作内存中进行读写操作,操作完后,再放回主内存。可见性就是如果一个变量被更新完放入主内存后,他会通知其他的线程,然后其他线程就会从主内存中拷贝最新的数据进自己的工作内存。理论就这么多,用两个例子来证明可见性。
import java.util.concurrent.TimeUnit;


public class Test {
    public static void main(String[] args) {
        Data data = new Data();

        /*
            我们在这里新建一个线程,这个线程调用了Data类的方法,修改了number的值,但是主线程Main发现不了
         */
        new Thread(()->{
            System.out.println(Thread.currentThread().getName() + " come in " +data.number);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            data.change();
            System.out.println(Thread.currentThread().getName() + " 修改已经完成~ " + data.number);
        },"A").start();

        while (data.number == 0){

        }
        System.out.println("已检测到number值发生变化~");
    }
}

/*
    资源类
 */
class Data {
    int number = 0;
    public void change() {
        number = 5;
    }
}

程序的运行结果可想而知,主线程一直在while中出不去,因为它没有更新number的值。


image.png

我们加上volatile后试试

class Data {
    volatile int number = 0;
    public void change() {
        number = 5;
    }
}
image.png

加上volatile之后,Main线程会被通知number的更新操作,所以看到这里相信你应该了解了volatile的保证可见性了。

  • 不保证原子性
    那么什么是原子性?原子性就是不可再分且不可简化,要么全部成功 ,要么全部失败。原子操作就是一旦这个操作开始之后,直到这个操作完成,都不能中断这个操作。
public class Test {
    public static void main(String[] args) {
        Data data = new Data();
        /*
            创建20个线程,让每个线程调用1000次add方法,如果保证原子性的话,答案是20000
         */
        for (int i = 1; i <= 20; i++) {
            new Thread(()->{
                for (int j = 1; j <= 1000; j++) {
                    data.add();
                }
            }).start();
        }
        /*  阻塞Main线程直到每个线程都完成计算任务后
            因为程序中本身就有Main线程和GC线程,如果线程数大于2,证明还有线程没计算完
         */
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(data.number);
    }
}

class Data {
    volatile int number = 0;
    
    public void add() {
        number++;
    }
}

程序运行结果并没有出乎意料,


image.png
image.png
image.png

由此可以证明volatile不保证原子性

  • 禁止指令重排序
    指令重排序是操作系统对程序编译的优化,在单线程程序下,指令重排序之后的结果不会改变,但是在多线程环境下,不能保证数据的一致性,volatile能禁止指令重排序

相关文章

网友评论

      本文标题:Volatile,你想知道的这里都有

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