线程安全----原子类

2020-07-23  本文已影响0人  任笙_8b8c
首先我们来看一段代码(模拟抢货):
图片.png

代码解释:下面代码模拟并发抢货过程,我们用了6个线程处理6万的货,按理来说应该是刚刚好库存全部为0.

public class RushOrder {  //库存类
   //我们库存总共6万
   int i =60000;
  public void order(){
          i--;
      }

   //模拟高并发状态下的抢货业务场景
   public static void main(String[] args) throws InterruptedException {
       RushOrder rushOrder =new RushOrder();
       for (int j = 0; j <6; j++) {
       //多个线程 6个线程一块去处理
           new Thread(
                   ()->{ //JDK1.8 的表达式  代表的就是run方法
                       //每个线程走一万次
                       for (int k = 0; k <10000 ; k++) {
                           rushOrder.order();
                       }
                   }
           ).start();
       }
       //休眠5秒
       Thread.sleep(5000);

       System.out.println("当前库存"+rushOrder.i);
   }

}

上面的 代码执行结果很显然并不是我们想要的执行结果
    第一次测试:当前库存20533
    第二次测试:当前库存26500
那这个i--操作在jvm中是怎么走的呢?


mysql.png
图解:

    这里的i--执行了三部操作,那为什么最终的值会不是0呢?原因很简单,因为i--它没有保证原子性

那什么是原子性呢?
那为什么i--就不满足原子性呢?(看下图)
mysql.png

图解:

       当线程1拿到i=10的值的时候,执行i--的操作时突然线程二就进来了,抢占了线程的执行权
线程2在共享变量拿到的值也是10,执行i--;然后最终来个线程执行完成后,put上去的值都是9,这就造成了为什么为什么每次执行货不是0的情况.

解决方案

  //我们库存总共6万
/*inti=60000;*/
AtomicIntegeri=newAtomicInteger(60000);//相当于i=60000但是它是一个原子操作类
publicvoidorder(){
//i--;
i.decrementAndGet();  //等同于i--它是一个原子性的
}

最终的执行结果为:当前库存0

那为什么decrementAndGet()就能保住线程安全呢?

图解:

为什么我们遇到这类原子性问题不去经常选择使用原子操作类,而去使用锁呢?

CAS机制的三大问题:
mysql.png
图解:
上一篇 下一篇

猜你喜欢

热点阅读