JDK源码分析-AtomicInteger
AtomicInteger可以看做Integer类的原子操作工具类。在java.util.concurrent.atomic包下,在一些使用场合下可以取代加锁操作提高并发性。接下来就从几个方面来介绍:
1.原子性和CAS。
2.CPU底层实现原理。
3.atomic包介绍。
4.源码分析。
原子性和CAS
原子性就是指某一个操作是不可拆分的,是一个整体必须要一次性全部执行完成要么就不执行。
CAS是Compare And Swap(比较并交换)。意思是当你要更新某个值的时候先要检查这个变量的当前值是不是改变了,如果改变了就不能更新,没改变就可以更新。
首先,CPU 会将内存中将要被更改的数据与期望的值做比较。然后,当这两个值相等时,CPU 才会将内存中的数值替换为新的值。否则便不做操作。最后,CPU 会将旧的数值返回。这一系列的操作是原子的。它们虽然看似复杂,但却是 Java 5 并发机制优于原有锁机制的根本。简单来说,CAS 的含义是“我认为原有的值应该是什么,如果是,则将原有的值更新为新值,否则不做修改,并告诉我原来的值是多少。
atomic包介绍
类的小工具包,支持在单个变量上解除锁的线程安全编程。此包中的类可将 volatile 值、字段和数组元素的概念扩展到那些也提供原子条件更新操作的类,其形式如下:
boolean compareAndSet(expectedValue, updateValue);
如果此方法(在不同的类间参数类型也不同)当前保持 expectedValue,则以原子方式将变量设置为 updateValue,并在成功时报告 true。此包中的类还包含获取并无条件设置值的方法,以及以下描述的较弱条件的原子更新操作 weakCompareAndSet。
原子访问和更新的内存效果一般遵循以下可变规则:
- get 具有读取 volatile 变量的内存效果。
- set 具有写入(分配)volatile 变量的内存效果。
- 除了允许使用后续(但不是以前的)内存操作,其自身不施加带有普通的非 volatile 写入的重新排序约束,lazySet 具有写入(分配)volatile 变量的内存效果。在其他使用上下文中,当为 null 时(为了垃圾回收),lazySet 可以应用不会再次访问的引用。
- weakCompareAndSet 以原子方式读取和有条件地写入变量但不创建任何 happen-before 排序,因此不提供与除 weakCompareAndSet 目标外任何变量以前或后续读取或写入操作有关的任何保证。
- compareAndSet 和所有其他的读取和更新操作(如 getAndIncrement)都有读取和写入 volatile 变量的内存效果。
设计原子类主要用作各种构造块,用于实现非阻塞数据结构和相关的基础结构类。compareAndSet 方法不是锁的常规替换方法。仅当对象的重要更新限定于单个 变量时才应用它。原子类不是 java.lang.Integer 和相关类的通用替换方法。它们不 定义诸如 hashCode 和 compareTo 之类的方法。
源码举例分析
AtomicInteger继承结构:
------java.util.concurrent.atomic.AtomicInteger
还实现了java.io.Serializable以便序列化使用,然后是字段的定义和初始化:
Unsafe里面定义了许多Native方法,通过JNI调用。value就是AtomicInteger代表的值,这里用volatile修饰用以保证value的可见性。
//源码 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;
AtomicInteger大概实现了20个左右的public方法,下面举几个有代表性的来分析:
1.get方法是用来获取当前最新的value。方法用final修饰是为了更进一步的保证线程安全。
/**
* Gets the current value.
*
* @return the current value
*/
public final int get() {
return value;
}
2.set方法是把value更新为一个新值。也是用final修饰。
/**
* Sets to the given value.
*
* @param newValue the new value
*/
public final void set(int newValue) {
value = newValue;
}
3.lazySet方法和set方法不同之处在于可以延时设置,就是在最后才设定新值。
/**
* Eventually sets to the given value.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
}
4.getAndSet方法是把新值设置为当前值然后返回旧值。
/**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
5.compareAndSet方法是首先比较当前值与期望值,相同才更新到新值。如果更新成功则返回true,否则返回false。
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
6.getAndIncrement方法是原子的把原值加一并且返回旧值。getAndDecrement类似。
/**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
7.getAndAdd方法是把原值加上某个值,并返回以前的值。
/**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the previous value
*/
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
8.incrementAndGet方法是把原值加一后返回新值。decrementAndGet类似。
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
9.getAndUpdate方法是根据一个定义的操作符来把当前值当第一个参数,传入的参数当做第二个参数更新value,返回旧值。updateAndGet是返回新值。 使用自旋的方式,调用了compareAndSet方法,只有返回了true才结束。
/**
* Atomically updates the current value with the results of
* applying the given function, returning the previous value. The
* function should be side-effect-free, since it may be re-applied
* when attempted updates fail due to contention among threads.
*
* @param updateFunction a side-effect-free function
* @return the previous value
* @since 1.8
*/
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return prev;
}
以上这些方法都是原子操作。
JDK源码分析-AtomicInteger的更多相关文章
- JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue
JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue 目的:本文通过分析JDK源码来对比ArrayBlockingQueue 和LinkedBlocki ...
- JDK 源码分析(4)—— HashMap/LinkedHashMap/Hashtable
JDK 源码分析(4)-- HashMap/LinkedHashMap/Hashtable HashMap HashMap采用的是哈希算法+链表冲突解决,table的大小永远为2次幂,因为在初始化的时 ...
- JDK源码分析(三)—— LinkedList
参考文档 JDK源码分析(4)之 LinkedList 相关
- JDK源码分析(一)—— String
dir 参考文档 JDK源码分析(1)之 String 相关
- JDK源码分析(2)LinkedList
JDK版本 LinkedList简介 LinkedList 是一个继承于AbstractSequentialList的双向链表.它也可以被当作堆栈.队列或双端队列进行操作. LinkedList 实现 ...
- 【JDK】JDK源码分析-LinkedHashMap
概述 前文「JDK源码分析-HashMap(1)」分析了 HashMap 主要方法的实现原理(其他问题以后分析),本文分析下 LinkedHashMap. 先看一下 LinkedHashMap 的类继 ...
- 【JDK】JDK源码分析-HashMap(1)
概述 HashMap 是 Java 开发中最常用的容器类之一,也是面试的常客.它其实就是前文「数据结构与算法笔记(二)」中「散列表」的实现,处理散列冲突用的是“链表法”,并且在 JDK 1.8 做了优 ...
- 【JDK】JDK源码分析-TreeMap(2)
前文「JDK源码分析-TreeMap(1)」分析了 TreeMap 的一些方法,本文分析其中的增删方法.这也是红黑树插入和删除节点的操作,由于相对复杂,因此单独进行分析. 插入操作 该操作其实就是红黑 ...
- 【JDK】JDK源码分析-Vector
概述 上文「JDK源码分析-ArrayList」主要分析了 ArrayList 的实现原理.本文分析 List 接口的另一个实现类:Vector. Vector 的内部实现与 ArrayList 类似 ...
随机推荐
- CentOS 7 x64 docker 使用点滴
CentOS 7 安装 docker yum search docker 查看是否 有docker包 yum info docker 版本为1.3.2 yum -y install docker ...
- StringBuffer与StringBuilder的作用与区别
来自为知笔记(Wiz)
- net stop 出现1060错误
net stop时出现1060错误,答案: 原来,net stop后面不能想当然地加上服务,而要在‘服务’里看看,那个服务究竟叫什么名字. 比如,我的mysql安装时不叫mysql,而是mysql5 ...
- tools_list
http://files.cnblogs.com/files/yansc/ExportQingtaoImage.rar
- LPC1768IAP(详解,有上位机)
之前说了stm32的iap编程,今天天气真好,顺手就来说说lpc1788的iap编程(没看前面的请查看stm笔记下的内容) 首先是flash的算法,lpc1768并没有寄存器来让我们操作flash,他 ...
- 【转】国外程序员整理的Java资源大全
Java几乎是许多程序员们的入门语言,并且也是世界上非常流行的编程语言.国外程序员Andreas Kull在其Github上整理了非常优秀的Java开发资源,推荐给大家.译文由ImportNew- 唐 ...
- 【ural1297】 Palindrome
http://acm.timus.ru/problem.aspx?space=1&num=1297 (题目链接) 题意 求最长回文子串 Solution 后缀数组论文题 穷举每一位,然后计算以 ...
- IOS9新特性之Contacts联系人
在以前iOS开发中,涉及联系人相关的编程,代码都非常繁琐,并且框架的设计也不是Objective-C风格的,这使开发者用起来非常的难受.在iOS9中,apple终于解决了这个问题,全新的Contact ...
- CSS实现背景透明而背景上的文字图片不透明
1.用图片则能兼容IE8和IE7 2.用颜色则不能兼容IE8和IE7,并且颜色层不能随着内容层自增长,只能设置一个固定高度 3.用颜色则颜色层不能包含内容层(图片和文字) <!-- wrap最外 ...
- JAVA8 HashMap 新特性
1. 链表解决冲突的方式: java中处理Hash散列后的冲突使用的是链表法: java8之前只是使用的简单Entry链表存储键值对.java8后,在Entry队列的长度大于8之后,会自动 ...