juc之volatile关键字及cas算法

1.共享变量可见性问题

  • java内存模型

image.png

  • 当一个线程操做了共享变量以后,仅仅会写入该线程缓存中,并不会及时写入主存中,那么别的线程此时从主存中获取到共享变量,就会致使异常。
  • volatile关键字:若是一个变量声明为volatile后,每一个线程操做共享变量后就会当即同步到主存中,此功能是底层硬件支持的。也就是说volatile关键字解决了共享变量的可见性问题,但没有解决变量的原子性以及互斥性。 原子类中的变量所有声明为volatile,保证线程可见性,原子类使用cas算法保证原子性。java

    public class VolatileDemo {
       public static void main(String[] args) {
    
           ThreadClass threadClass = new ThreadClass();
           Thread thread = new Thread(threadClass);
           thread.start();
    
           while (true){
               if (threadClass.shareVar){//在这里main线程访问共享变量,该共享变量是main线程的变量副本
                   System.out.println("ShareVariableClass.shareVar:" + threadClass.shareVar);
                   break;
               }
           }
       }
    }
    
    class ThreadClass implements Runnable{
    
       public volatile boolean shareVar = false;
    
       @Override
       public void run() {
           try {
               Thread.sleep(200);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           this.shareVar = true;
           System.out.println("sharVar change to " + shareVar);
       }
    }

        结果以下,结果中打印的顺序会不一致。
    image.png算法

2.CAS算法

    CAS:全称compare and swap,比较并交换。当多个线程操做共享变量的时候,每一个线程的操做都写入主存中,就会致使主存中的共享变量不可以保证原子性。若是要操做一个变量s进行+1操做,在+操做以前,获取主存中s的值(经过volatile关键字保证可见性)做为指望值expectValue,将s进行+1操做后,写入主存以前经过将目前的主存值和expectValue值作比较,若是相同则将s+1的值写入主存,若是不相等,则重复进行上述步骤。缓存

    以AtomicInteger举例ide

AtomicInteger atomicInteger = new AtomicInteger(10);
int andIncrement = atomicInteger.getAndIncrement();

    cas操做最终调用的方法是Unsafe类中的native方法调用,除了Integer类型的原子操做,还有Boolean等的类型操做,但调用是以下三个方法来保证原子性。boolean类型是经过转换为int类型来进行操做的。
    
image.png
    
image.pngthis

    全部原子类以下
image.pngatom

相关文章
相关标签/搜索