java源码-AtomicInteger
开篇
AtomicInteger位于java.util.concurrent.atomic包下,是java提供给的可以保证数据的原子性操作的一个类。
Atomicxxxx系列主要核心在于Unsafe这个类的运用保证线程安全,而Unsafe这个类应该是通过JNI调用的底层实现。
关于unsafe类可以看看揭秘sun.misc.Unsafe,虽然我还是没怎么看懂。记住unsafe这个东西很重要,不过据说在jdk9之后应该会被弃用了。
AtomicInteger类构造器
AtomicInteger类构造器有两个:
- 无参构造函数采用默认值初始化为0
- 有参数构造函数直接用initialValue来value的
- AtomicInteger的关键逻辑在于static代码快中通过unsafe接口初始化value的内存地址,后续直接通过内存地址进行操作。
另外我们需要注意到value是用volatile进行修饰保证变量的可见性,这个有空一定要仔细研究研究。
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; // value值初始化为initialValue public AtomicInteger(int initialValue) { value = initialValue; } // value的值为默认值为0 public AtomicInteger() { } }
AtomicInteger的get操作
AtomicInteger的get操作还是比较有意思的,总共非几大类:
- get()方法直接返回值
- getAndIncrement()、getAndDecrement()、getAndAdd()、getAndUpdate()先返回旧值后对旧值执行加减操作。
- incrementAndGet()、decrementAndGet()、addAndGet()、updateAndGet()先执行加减操作后返回新值。
- 底层操作unsafe.getAndAddInt()的实现细节借助于unsafe的compareAndSwapInt()方法保证只有在旧值为v的情况下才能更新为v+delta值。
public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, v + delta)); return v; } --------------------------------------------------------------- public final int get() { return value; } public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } public final int getAndDecrement() { return unsafe.getAndAddInt(this, valueOffset, -1); } public final int getAndAdd(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta); } public final int getAndUpdate(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return prev; } public final int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction) { int prev, next; do { prev = get(); next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return prev; } --------------------------------------------------------------- public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } public final int decrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, -1) - 1; } public final int addAndGet(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta) + delta; } public final int updateAndGet(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return next; } public final int accumulateAndGet(int x, IntBinaryOperator accumulatorFunction) { int prev, next; do { prev = get(); next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return next; }
AtomicInteger的set操作
AtomicInteger的set操作基本上也分为两大类:
- 直接set设置value值
- 通过unsafe的api接口实现原子性写操作
public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, v + delta)); return v; } ------------------------------------------------------------------ public final void set(int newValue) { value = newValue; } public final void lazySet(int newValue) { unsafe.putOrderedInt(this, valueOffset, newValue); } public final int getAndSet(int newValue) { return unsafe.getAndSetInt(this, valueOffset, newValue); } public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } public final boolean weakCompareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
参考文章
揭秘sun.misc.Unsafe
非阻塞同步算法与CAS(Compare and Swap)无锁算法
为什么volatile不能保证原子性而Atomic可以?
彻底了解内存屏障

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
ArcGIS API for JavaScript4.x 之加载2D、3D地图
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gisdoer/article/details/81545607 ArcGIS API for JavaScript 之加载2D、3D地图 点击查看文章
- 下一篇
[剑指offer] 从尾到头打印链表
本文首发于我的个人博客:尾尾部落 题目描述 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。 解题思路 一种方法是利用栈来实现; 另外一种方法是利用三个指针把链表反转,关键是 r 指针保存断开的节点。 image 参考代码 /** * public class ListNode { * int val; * ListNode next = null; * * ListNode(int val) { * this.val = val; * } * } * */ import java.util.ArrayList; public class Solution { public ArrayList<Integer> printListFromTailToHead(ListNode listNode) { if(listNode == null) return new ArrayList<Integer>(); ListNode head = listNode; ListNode cur = listNode.next; while( cur!= nu...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS关闭SELinux安全模块
- CentOS7设置SWAP分区,小内存服务器的救世主
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程