Java的多线程学习-volatile

70 阅读1分钟

特点

  • 使用MESI协议(使得数据被修改了,状态可被修改可以立即看到),保证了线程间的可见性,但无法保证原子性
  • 禁止指令重排(指令重排是指多个指令的并发执行,提高了效率),但会影响可见性,使用内存屏障实现,在多线程下,禁止指令重排可以避免后续的线程获得未初始化的变量

无法保证原子一致性

static  volatile int num=0;
public static void main(String[] args) throws InterruptedException, ExecutionException {
    for(int i=0;i<1000;i++){
        new Thread(()->{
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            num = num+1 ;
            System.out.println(num);
        }).start();
        System.out.println(num);

    }



}

如下图所示,volatile无法保证原子一致性

image.png

volatile存在的意义

volatile最大的意义是禁止cpu指令重排,避免后面的线程访问前面线程的还未初始化的变量,如以下代码


class NumStoreDemo{
    private NumStoreDemo() {
    }
    private static volatile NumStoreDemo numStore;
    private static volatile  int num = 0;
    private static volatile  int nums = 0;
    public   void add() throws InterruptedException {
        synchronized (this){
           num=num+1;
            /*System.out.println(num);*/ } }
    public  static NumStoreDemo instance() throws InterruptedException {
        if(numStore==null){
            synchronized (NumStoreDemo.class){
                if(numStore==null){
                    numStore=new NumStoreDemo();
                    nums=nums+1;
                    System.out.println("初始化 "+numStore+","+nums);
                }

                } }
        return  numStore;
    }
}

image.png