juc之volatile关键字及cas算法

1.共享变量可见性问题

  • java内存模型

image.png

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

    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举例

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

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

    所有原子类如下
image.png

你可能感兴趣的:(java,volatile,cas)