博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程九 原子类
阅读量:5235 次
发布时间:2019-06-14

本文共 3685 字,大约阅读时间需要 12 分钟。

JDK5提供原子类,及其操作

AtomicXXX是通过CAS , Unsafe.compareAndSwapInt实现的

简单分析一下原子类是如果使用cas,无锁却保证线程安全的

每条线程都有自己的本地缓存,他们要想操作变量,首先是把变量复制到自己的缓存中,然后处理数据,数据处理结束后,将自己缓存的数据刷新会主存,而CAS则就是利用这一点实现的

下面是看Unsafe.class源码,可以看到,下面几个cas方法,全部是native,也就是本地方法

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

随便找一个方法

//var1 就是方法的调用者  var2:当前的值  var4需要加的值   public final int getAndAddInt(Object var1, long var2, int var4) {    int var5;     do {        //此方法(同样也是本地方法),返回当前 内存中var1对象里面的 var2的值        var5 = this.getIntVolatile(var1, var2);        //判断var1里面的值var2是否就是var5,如果相等我们更新为 var5+var4 ,否则继续循环尝试修改    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));    return var5;}

如何使用呢?

AtomicLong atomicLong = new AtomicLong(); atomicLong.getAndIncrement();

解释一下,为了保证数据的安全性,根据JMM内存模型设计出了cas算法,compareAndSwap先比较,再更换值,现在看我们上面随便找的方法, 里面有一个do-while循环,其实基本上所有设及cas算法的方法,都采用了这个循环,它保证我们可以做出足够多次数的判断


  • 原子更新boolean

    下面使用它完成确保某段代码只执行一次

public class demo {// 原子更新boolean  初始化为falsepublic static AtomicBoolean atomicBoolean = new AtomicBoolean(false);//请求总数public static int clientTotal = 5000;//同时并发执行的线程数public static int threadPool = 200;public static void main(String[] args) throws InterruptedException {    ExecutorService executor = Executors.newCachedThreadPool();    //每次两百次并发    Semaphore semaphore = new Semaphore(threadPool);    //计数器 执行五千次    CountDownLatch countDownLatch = new CountDownLatch(clientTotal);    for (int i=0;i

查看结果,哪怕执行5000次,每次200的并发,if()里面的代码还是只执行了一次

值更新了atomicBoolean==true
类名 描述
AtomicInteger 用原子方式更新的 int 值
AtomicLong 用原子方式更新的 long 值
AtomicBoolean 原子方式更新的 boolean 值
  • 原子更新基本类型
类名 描述
AtomicInteger 用原子方式更新的 int 值
AtomicLong 用原子方式更新的 long 值
AtomicBoolean 原子方式更新的 boolean 值
  • 原子更新数组
类名 描述
AtomicIntegerArray 用原子方式更新其元素的 int 数组
AtomicLongArray 用原子方式更新其元素的 long 数组
  • 原子更新抽象类型
类名 描述
AtomicReference 用原子方式更新的对象引用
AtomicStamptedReference 增加了版本号机制,解决了CAS里面的ABA问题

...

注意: 针对的是V型的对象,而不是对象里面的字段

  • 原子更新字段
    类名 | 描述 |
    ---|---
    AtomicIntegerFieldUpdater |基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新
    |AtomicLongFieldUpdater |基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新

注意: 针对的是V型的对象,而不是对象里面的字段

JDK8 新增原子类:

  • DoubleAdder
  • LongAdder 弥补AtomicLong在高并发情况下的性能低问题

    AtomicLong里面仅仅有一个Long类型的值,多个线程并发访问,当一个线程获取到锁修改Long值时,很容易成功,但是当很多个线程并发修改它的值,很可能陷入do-while死循环,消耗性能

LongAdder里面有一组值,每个值都是一个cell,所有的cell加起来是一个base,例如Base如果是5,那么cell可能被分解成2 3,将原来修改一点的高压力分散在不同点上,多线程并发访问去抢占修改cell.在sum()方法中汇总,但线程的话,直接得出结果,从而提高性能

...

原子类并不完全安全!

**虽然addAndGet()方法是原子的,多线程中,方法的调用是无序的

public class TextAtomicService {    public static AtomicLong atomicLong = new AtomicLong();    public void add(){        System.out.println(Thread.currentThread().getName()+"加了100之后的值为:"+atomicLong.addAndGet(100));        atomicLong.addAndGet(1);    }}//public class AtomicText extends Thread{private  TextAtomicService textAtomicService;public AtomicText(TextAtomicService t1){    textAtomicService=t1;}@Overridepublic void run(){    textAtomicService.add();}public static void main(String[] args) {    TextAtomicService textAtomicService = new TextAtomicService();    AtomicText[] atomicTexts = new AtomicText[5]; try {    for (int i=0;i<5;i++){        atomicTexts[i]=new AtomicText(textAtomicService);    }    for (int i=0;i<5;i++){        atomicTexts[i].start();    }    Thread.sleep(2000);    } catch (InterruptedException e) {        e.printStackTrace();    }}}

可能出现这种情况,就是当前线程执行完addAndGet(100)之后,cpu的执行权被另一条线程抢走,又执行addAndGet(100),这样的结果就是200,而不是我们预想的202

解决方法就是添加Synchronized关键字,同步化!

转载于:https://www.cnblogs.com/ZhuChangwu/p/11150342.html

你可能感兴趣的文章
实验6,继承
查看>>
全局解释器锁--GIL
查看>>
开博篇
查看>>
代码之美1:使用策略模式来编写solr 排序方法
查看>>
Python 练习判断
查看>>
Python 类实例化
查看>>
JS高级 - 面向对象4(json方式面向对象)
查看>>
Java反射之修改常量值
查看>>
用UIWebView加载本地图片和gif图
查看>>
jmeter远程分布执行遇到的网卡坑(A Test is currently running,stop or ....)
查看>>
Python正则表达式中的re.S
查看>>
Xcode 中设置部分文件ARC支持
查看>>
iOS-解决iOS8及以上设置applicationIconBadgeNumber报错的问题
查看>>
亡灵序曲-The Dawn
查看>>
实验五
查看>>
leetcode 347 priority,map的使用
查看>>
vue 校验插件 veeValidate使用
查看>>
WCF应用(二)
查看>>
jquery.pagination.js分页
查看>>
[BZOJ4009][HNOI2015]接水果(整体二分)
查看>>