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 和相关类的通用替换方法。它们 定义诸如 hashCodecompareTo 之类的方法。

  源码举例分析

  AtomicInteger继承结构:

  -java.lang.Object

  ---java.lang.Number

  ------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的更多相关文章

  1. JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue

    JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue 目的:本文通过分析JDK源码来对比ArrayBlockingQueue 和LinkedBlocki ...

  2. JDK 源码分析(4)—— HashMap/LinkedHashMap/Hashtable

    JDK 源码分析(4)-- HashMap/LinkedHashMap/Hashtable HashMap HashMap采用的是哈希算法+链表冲突解决,table的大小永远为2次幂,因为在初始化的时 ...

  3. JDK源码分析(三)—— LinkedList

    参考文档 JDK源码分析(4)之 LinkedList 相关

  4. JDK源码分析(一)—— String

    dir 参考文档 JDK源码分析(1)之 String 相关

  5. JDK源码分析(2)LinkedList

    JDK版本 LinkedList简介 LinkedList 是一个继承于AbstractSequentialList的双向链表.它也可以被当作堆栈.队列或双端队列进行操作. LinkedList 实现 ...

  6. 【JDK】JDK源码分析-LinkedHashMap

    概述 前文「JDK源码分析-HashMap(1)」分析了 HashMap 主要方法的实现原理(其他问题以后分析),本文分析下 LinkedHashMap. 先看一下 LinkedHashMap 的类继 ...

  7. 【JDK】JDK源码分析-HashMap(1)

    概述 HashMap 是 Java 开发中最常用的容器类之一,也是面试的常客.它其实就是前文「数据结构与算法笔记(二)」中「散列表」的实现,处理散列冲突用的是“链表法”,并且在 JDK 1.8 做了优 ...

  8. 【JDK】JDK源码分析-TreeMap(2)

    前文「JDK源码分析-TreeMap(1)」分析了 TreeMap 的一些方法,本文分析其中的增删方法.这也是红黑树插入和删除节点的操作,由于相对复杂,因此单独进行分析. 插入操作 该操作其实就是红黑 ...

  9. 【JDK】JDK源码分析-Vector

    概述 上文「JDK源码分析-ArrayList」主要分析了 ArrayList 的实现原理.本文分析 List 接口的另一个实现类:Vector. Vector 的内部实现与 ArrayList 类似 ...

随机推荐

  1. Golang学习笔记:包制作

    golang的包跟java as js之类的大不一样,一定要存在GOPATH里面,GOPATH是专门用于存放golang第三方的库,里面有两个文件夹, src:源代码目录 pkg:编译后的第三方包,这 ...

  2. Quick Cocos2dx 与 Eclipse 连真机debug遇到的问题

    今天下午解决了因为偷懒一直忍受的两个让我不爽很久了的问题: 1Eclipse无法连接手机调试的问题. 在设备管理器中看到的Android设备有黄色的感叹号, 说明驱动不是最新的. 按照网上搜到的解决方 ...

  3. EQueue - 一个C#写的开源分布式消息队列的总体介绍(转)

    源: EQueue - 一个C#写的开源分布式消息队列的总体介绍 EQueue - 一个纯C#写的分布式消息队列介绍2 EQueue - 详细谈一下消息持久化以及消息堆积的设计

  4. iOS 消息推送原理及实现总结

    在实现消息推送之前先提及几个于推送相关概念,如下图:1. Provider:就是为指定IOS设备应用程序提供Push的服务器,(如果IOS设备的应用程序是客户端的话,那么Provider可以理解为服务 ...

  5. struts2拦截器-自定义拦截器,放行某些方法(web.xml配置)

    一.web.xml配置 <filter> <filter-name>encodingFilter</filter-name> <filter-class> ...

  6. 1)Java学习笔记:接口和抽象类的异同

    Java接口和抽象类很像,他们有哪些相同点和异同点呢,下面我们做一个小结 相同 ① 都不能被实例化,都位于继承树的顶端,用于被实现或者继承 ② 都可以包含抽象方法,实现接口或者继承抽象类的普通子类都必 ...

  7. CentOS 7 上面安装PowerShell

    看了文章 爱上PowerShell , 就想在CentOS 7上面试试PowerShell , 本文记录了在CentOS 7.2上安装Powershell 的过程. 首先我们要从github上下载最新 ...

  8. 安卓selector

    定义styles.xml <?xml version="1.0" encoding="utf-8"?> <resources> < ...

  9. 在DataGrid中实现Button Command

    Command="{Binding butCommand}"会默认查找ListViewItems中对象的属性,而你的ListViewItems中对象应该不包括butCommand属 ...

  10. cpu95%,查找问题sql

    收到一封告警邮件: Load average on xxx_server reached critical threshold values - 169.5 Current Load Avg = 16 ...