JAVA多线程之AtomicInteger类
image.png
前言
atomic翻译为原子的,所以顾名思义,这个AtomicInteger的存在就是在Integer的基础上支持了整型变量的原子性。变量的原子性在我们解决多线程问题的时候都是不可避免需要着重考虑的一个问题,解决不好极可能导致整个逻辑变形,业务解决异常。而且此类问题在发现后再解决会比较耗费时间,影响生产环境的稳固,所以应该在设计时就充分考虑多线程问题。
一、基础必备-Unsafe
1.1 内存开拓与释放
大家都知道java不能直接操作内存,屏蔽了指针等操作方法,Unsafe方法里面提供了allocateMemory,freeMemory等开拓空间和释放空间的本地方法(本地方法不限制实现语言类型)入口
1.2 元素定位
(1)staticFieldOffset 返回静态属性的偏移地址
(2)objectFieldOffset 返回非静态属性的偏移地址
(3)staticFieldBase静态属性的基地址,即类中第一个静态属性的地址,配合偏移地址就能找到静态属性的实际地址了
(4)arrayBaseOffset 数组首个元素的偏移地址
(5)arrayIndexScale 数组中元素的相对于首个元素的偏移量,首个元素偏移地址加偏移量就能知道元素的具体地址了
1.3 CAS
在concurrent包中有很多地方都用到了cas操作,最终都是用了Unsafe里面的cas操作,Unsafe里面有三个相关的方法入口
(1)compareAndSwapObject(Object var1, long var2, Object var4, Object var5)
(2)compareAndSwapInt(Object var1, long var2, int var4, int var5)
(3)compareAndSwapInt(Object var1, long var2, int var4, int var5)
这三个方法相似,每个方法都有四个入参:操作对象,对象中的元素偏移地址,元素期望值,将要变更的目标值,即该方法对var1中偏移地址为var2的元素做变更,当它与var4相等时,将它变更成var5,返回true,否则返回false。
二、常用方法分析
进入到类中我们可以看到一个静态域的初始化过程,有两个注意点
static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } private volatile int value;(1)获取到了value属性的偏移地址
(2)value是被volatile修饰的,是线程可见的,volatile修饰的变量在读写时存在内存屏障,写入时会CPU缓存数据刷到内存中,读取时直接读取内存数据,同时还能防止指令重排序
2.1 get和set方法
普通的get和set方法,除了volatile使得属性可见之外和Integer类没啥区别
2.2 lazySet方法
前面说到volatile修饰的属性有一系列的操作保证了变量的线程可见性,所以一定会影响代码的执行效率,这个方法就是在不需要让共享变量的修改立刻让其余线程可见的时候,以设置普通变量的方式来修改共享状态,可以减少不必要的内存屏障,从而提高程序执行的效率。
PS:基本上很少用到,由于普通的使用的话一定优先考虑Integer。
2.3 getAndSet
先获取内存中的当前变量值,而后不断的利用cas去升级,直到升级成功,返回升级前的变量值。注意这个升级前的值是在升级前内存中最新的,也就是不会被其余线程有冲突,否则cas不会成功。
public final int getAndSetInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var4)); return var5; }2.4 compareAndSet(int expect, int update)
假如expect值和当前内存中的值是一样的,则将update值升级到内存中
2.5 weakCompareAndSet
和上面的方法一模一样,换了个名字而已
2.6 getAndIncrement
获取当前变量的值,而后+1,但是返回的值是+1前的值
public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { //获取当前变量的值 var5 = this.getIntVolatile(var1, var2); // 直到cas成功再退出循环 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }2.7 getAndDecrement
获取当前变量的值,而后-1,但是返回的值是-1前的值
2.8 getAndAdd(int delta)
获取当前变量的值,而后加上delta,返回加上delta之前的值
2.9 incrementAndGet
对当前变量执行+1,而后返回+1后的值
2.10 decrementAndGet
对当前变量执行-1,而后返回-1后的值
2.11 addAndGet(int delta)
给当前变量+delta,而后返回+delta的值
其余
其余的几个方法也大致相同,只不过入参改成了函数而已,熟习函数式编程的童鞋应该很容易了解
image.png
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » JAVA多线程之AtomicInteger类