本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。

并发编程系列博客传送门


java.util.concurrent.atomic中,普通的原子类型有以下四种:

  • AtomicBoolean:提供对基本数据类型boolean的原子性更新操作。
  • AtomicInteger:提供对基本数据类型int的原子性更新操作。
  • AtomicLong:提供对基本数据类型long的原子性更新操作。
  • AtomicReference:这是一个泛型类,提供对引用类型的原子性更新操作。

数组相关的操作类有:

  • AtomicLongArray:提供对int[]数组元素的原子性更新操作。
  • AtomicIntegerArray:提供对long[]数组元素的原子性更新操作。
  • AtomicReferenceArray:提供对引用类型[]数组元素的原子性更新操作。

由于上面的原子操作类的实现原理差不多,我们这边就选择AtomicInteger来分析。

代码分析

构造函数

public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L; //Unsafe类提供底层的CAS机制
private static final Unsafe unsafe = Unsafe.getUnsafe();
//valueOffset是value值的内存地址值偏移值,这个值的作用是获取value在主内存中的值
private static final long valueOffset;
//类加载的时候获取valueOffset的值
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
} //AtomicInteger具体的值存放在这个变量中,
//这个变量使用volatile修饰,具有可见性
private volatile int value; public AtomicInteger(int initialValue) {
value = initialValue;
} //默认为0
public AtomicInteger() {
}
}

get和set方法分析

//value使用volatile修饰,每次能拿到最新值
public final int get() {
return value;
} //value使用volatile修饰,赋值操作具有原子性,所以这个操作也是线程安全的
//这个方法和compareAndSet方法的区别是:compareAndSet方法会判断预期值和当前值,而set方法不会做任何判断,直接更新
// set方法不会在意原始值是多少,而compareAndSet会确保主内存中的值和预期值相等才更新。
public final void set(int newValue) {
value = newValue;
} //这个方法可能比较令人疑惑,我查了下unsafe的putOrderedInt方法,如下 /** Sets the value of the integer field at the specified offset in the
* supplied object to the given value. This is an ordered or lazy
* version of <code>putIntVolatile(Object,long,int)</code>, which
* doesn't guarantee the immediate visibility of the change to other
* threads. It is only really useful where the integer field is
* <code>volatile</code>, and is thus expected to change unexpectedly.
*/
上面的意思大致是:putOrderedInt方法不保证可见性,只有在变量是volatile修饰时才有用,
我们这边的value变量就是用volatile修饰的,所以我认为AtomicInteger的`set`方法和`lazySet`方法
功能是一致的。
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
} //将value设置成给定值,并返回旧值
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
//使用CAS机制更新
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//使用CAS机制更新
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//CAS加1,并且返回原始值
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
//CAS减1,并且返回原始值
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
//CAS加减delta值,并且返回原始值
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
//CAS加1,并且返回最新值
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
//CAS减1,并且返回最新值
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
//CAS加减delta值,并且返回最新值
public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}

策略更新

下面几个方法个人觉得不是很有用,和上面的区别就是更新的值不是穿进去的,而是通过IntUnaryOperatorIntBinaryOperator接口算出来的。

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 updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
} 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 accumulateAndGet(int x,IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return next;
}

简单总结

总体来说,AtomicBoolean、AtomicInteger、AtomicLong和AtomicReference原理比较简单:使用CAS保证原子性,使用volatile保证可见性,最终能保证共享变量操作的线程安全。

AtomicLongArray、AtomicIntArray和AtomicReferenceArray的实现原理略有不同,是用CAS机制配合final机制来实现共享变量操作的线程安全的。感兴趣的同学可以自己分析下,也是比较简单的。

最新文章

  1. 洛谷 P1026 统计单词个数 Label:dp
  2. phonegap android 输入法弹出会遮盖表单框的解决办法
  3. SCOI 2013 密码 &amp; 乱搞
  4. SQL&amp;&amp;LINQ:左(外)连接,右(外)连接,内连接,完全连接,交叉连接,多对多连接
  5. 基于Selenium2+Java的UI自动化(4) - WebDriver API简单介绍
  6. Arithmetic Expression
  7. Etcd学习(一)安装和.NETclient測试
  8. GITLAB管理自己的私有源码
  9. mysql的导入和导出
  10. python进阶学习(二)
  11. 520. Detect Capital
  12. javascript 面向对象(多种创建对象的方式)
  13. 利用Python进行数据分析——重要的Python库介绍
  14. xshell连接centos与ubuntu
  15. 封装一个redis操作类来操作hash格式
  16. python+selenium页面自动化 元素定位实际遇到的各种问题(持续更新)
  17. python进程基础
  18. 在grails中远程调用action
  19. vs widows服务的调试
  20. linux每日命令(37):top命令

热门文章

  1. 解决pip is configured with locations that require TLS/SSL问题
  2. python如何自动发送邮件
  3. 洛谷 2152 [SDOI2009]SuperGCD
  4. Ext.FormPanel-----FieldSet的用法
  5. poj 3862 &amp;&amp; LA 4589 Asteroids (三维凸包+多面体重心)
  6. jar包运行
  7. C#的循环语句(四)
  8. 央行下属的上海资信网络金融征信系统(NFCS)签约机构数量突破800家
  9. P1080 探测器
  10. P1044 最大值最小化