博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AtomicInteger原理分析
阅读量:2714 次
发布时间:2019-05-13

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

前言

AtomicInteger的本质:自旋锁+CAS原子操作

 

1. 源码分析

public class AtomicInteger extends Number implements java.io.Serializable {    private static final long serialVersionUID = 6214790243416807050L;    // setup to use Unsafe.compareAndSwapInt for updates    private static final Unsafe unsafe = Unsafe.getUnsafe();    private static final long valueOffset;    static {        try {            valueOffset = unsafe.objectFieldOffset                (AtomicInteger.class.getDeclaredField("value"));        } catch (Exception ex) { throw new Error(ex); }    }    private volatile int value;

使用Unsafe类,定义偏移量 valueOffset,类加载就初始化。用于原子操作CAS

Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。

 

AtomicInteger的本质 int value,私有的

这里要注意使用了volatile修饰,volatile 关键字

1.1 JDK1.7及以前

public final int incrementAndGet() {    //自旋锁    for (;;) {        //获取volatitle修饰的变量,最新的主存值        int current = get();        //理论上自增值        int next = current + 1;                if (compareAndSet(current, next))            return next;    }}public final boolean compareAndSet(int expect, int update) {    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}

1.获取volatitle修饰的变量,最新的主存值

2.value+1作为自增值

3. compare value是否就是主存值,是,set next,return next;否,循环下一次

1.2 JDK1.8及以后

/**     * Atomically increments by one the current value.     *     * @return the updated value     */    public final int incrementAndGet() {        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;}

下面看getAndAddInt方法

public final int getAndAddInt(Object obj, long valueOffset, int delta) {        int expect;        //自旋        do {            //获取主存的值            expect = this.getIntVolatile(obj, valueOffset);        //CAS操作        } while(!this.compareAndSwapInt(obj, valueOffset, expect, expect + delta));        //返回旧值        return expect;    }

封装了自旋锁 

直接封装unsafe方法中了,保证原子性,unsafe是JDK私有的我们不能调用

2. 优缺点

AtomicInteger的优点

1.乐观锁,性能较强,利用CPU自身的特性保证原子性,即CPU的指令集封装compare and swap两个操作为一个指令来保证原子性。

2.适合读多写少模式

但是缺点明显

1.自旋,消耗CPU性能,所以写的操作较多推荐sync

2.仅适合简单的运算,否则会产生ABA问题,自旋的时候,别的线程可能更改value,然后又改回来,此时需要加版本号解决,JDK提供了AtomicStampedReference和AtomicMarkableReference解决ABA问题,提供基本数据类型和引用数据类型版本号支持

 

 

 

 

转载地址:http://mslvd.baihongyu.com/

你可能感兴趣的文章
BeanFactoryPostProcessor的使用
查看>>
多线程自增运算的原子性与可见性分析
查看>>
设计模式之中介者模式
查看>>
TPC,TPCC,TPMC(计算机性能衡量指标) -----
查看>>
别错过!漂亮又好用的思维导图模板
查看>>
快学起这4类智能图形,玩转PPT!
查看>>
如何有效地进行资料整理?
查看>>
项目管理高手常用的10种图表!
查看>>
EasyUI之multiple多选框禁用某些项选中
查看>>
EasyUI之多选框获取所有选中节点某项属性
查看>>
Oracle之DML操作表(insert/update/delete/truncate)
查看>>
Mac 电脑鼠标和触摸板滚动方向不一致的问题
查看>>
LeetCode 62. Unique Paths LeetCode 63 Unique Paths II 不同的路径之二
查看>>
LeetCode 66. Plus One
查看>>
LeetCode 74. Search a 2D Matrix
查看>>
【已解决】 78. Subsets【39、40未解决】
查看>>
创建第一个android项目
查看>>
Excel 使用过程中碰到的问题处理
查看>>
阿里云负载均衡SLB--报错502 Bad Gateway 的解决方案
查看>>
Monte Carlo 方法求解π的近似值
查看>>