volatile关键字解析

并发编程中的三个概念

原子性,可见性,有序性.

原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。

可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

有序性:即程序执行的顺序按照代码的先后顺序执行。

volatile关键字的两层语义

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

2)禁止进行指令重排序。

使用条件

两个条件:

对变量的写操作不依赖于当前值。

该变量没有包含在具有其他变量的不变式中。

volatile保证不了线程安全

想要线程安全必须保证原子性,可见性,有序性。而volatile只能保证可见性和有序性

缓存一致性协议

如果我写入之后发现这是共享变量就使得其他cpu缓存了的值失效,让它再次去内存中读取。

贴一段代码

public class VolatileUnsafe {

  private static class VolatileVar implements Runnable {

      private volatile int a = 0;

      @Override

      public void run() {

          String threadName = Thread.currentThread().getName();

          a = a++;

          System.out.println(threadName+":======"+a);

          SleepTools.ms(100);

          a = a+1;

          System.out.println(threadName+":======"+a);

      }

}

    public static void main(String[] args) {

      VolatileVar v = new VolatileVar();

        Thread t1 = new Thread(v);

        Thread t2 = new Thread(v);

        Thread t3 = new Thread(v);

        Thread t4 = new Thread(v);

        t1.start();

        t2.start();

        t3.start();

        t4.start();

    }

}


 这样如果有一个变量i = 0用volatile修饰,两个线程对其进行i++操作,如果线程1从内存中读取i=0进了缓存,然后把数据读入寄存器,之后时间片用完了,然后线程2也从内存中读取i进缓存,因为线程1还未执行写操作,内存屏障是插入在写操作之后的指令,意味着还未触发这个指令,所以缓存行是不会失效的。然后线程2执行完毕,内存中i=1,然后线程1又开始执行,然后将数据写回缓存再写回内存,结果还是1。

主要原因:

就是volatile只有再执行写操作的时候次才会缓存失效而不是读时就应该失效!

你可能感兴趣的:(volatile关键字解析)