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

并发编程系列博客传送门


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机制来实现共享变量操作的线程安全的。感兴趣的同学可以自己分析下,也是比较简单的。

AtomicXXX系列类使用分析的更多相关文章

  1. [UML]UML系列——类图class的泛化关系

    系列文章       [UML]UML系列——用例图Use Case       [UML]UML系列——用例图中的各种关系(include.extend)       [UML]UML系列——类图C ...

  2. Python科普系列——类与方法(下篇)

    书接上回,继续来讲讲关于类及其方法的一些冷知识和烫知识.本篇将重点讲讲类中的另一个重要元素--方法,也和上篇一样用各种神奇的例子,从原理和机制的角度为你还原一个不一样的Python.在阅读本篇之前,推 ...

  3. MapReduce剖析笔记之八: Map输出数据的处理类MapOutputBuffer分析

    在上一节我们分析了Child子进程启动,处理Map.Reduce任务的主要过程,但对于一些细节没有分析,这一节主要对MapOutputBuffer这个关键类进行分析. MapOutputBuffer顾 ...

  4. [UML]UML系列——类图class的关联关系(聚合、组合)

    关联的概念 关联用来表示两个或多个类的对象之间的结构关系,它在代码中表现为一个类以属性的形式包含对另一个类的一个或多个对象的应用. 程序演示:关联关系(code/assocation) 假设:一个公司 ...

  5. [UML]UML系列——类图class的依赖关系

    相关文章          [UML]UML系列——用例图Use Case       [UML]UML系列——用例图中的各种关系(include.extend)       [UML]UML系列—— ...

  6. [UML]UML系列——类图class的实现关系Realization

    系列文章 [UML]UML系列——用例图Use Case       [UML]UML系列——用例图中的各种关系(include.extend)       [UML]UML系列——类图Class   ...

  7. 【建模】UML类关系分析

    一.UML类关系分析 1.关联(asociation) 一般是一方拥有另一方对象的指针.箭头的方向是访问方向. 2.聚合(Aggregation)和组合(Composition) 聚合和关联一般不做区 ...

  8. 使用AES加密的勒索类软件分析报告

    报告名称:  某勒索类软件分析报告    作者:        李东 报告更新日期: 样本发现日期: 样本类型: 样本文件大小/被感染文件变化长度: 样本文件MD5 校验值: da4ab5e31793 ...

  9. String类原理分析及部分方法

    //String类原理分析及部分方法 //http://www.cnblogs.com/vamei/archive/2013/04/08/3000914.html //http://www.cnblo ...

随机推荐

  1. @NOI模拟2017.06.30 - T1@ Left

    目录 @description@ @solution@ @accepted code@ @details@ @description@ JOHNKRAM 最近在研究排序网络,但他发现他不会制作比较器, ...

  2. 微信小程序封装自定义弹窗

    最近在做小程序的登录,需要同时获取用户手机号和头像昵称等信息,但是小程序又不支持单个接口同时获取两种数据,因此想到自定义一个弹窗,通过弹窗按钮触发获取手机号事件.记录一下. 具体代码如下: 业务代码中 ...

  3. CSS属性Display(显示)和Visibility(可见性)

    隐藏一个元素可以通过把display属性设置为“none”,或把visibility属性设置为“hidden”.但是请注意,这两种方法会产生不同的效果. Visibility:hidden可以隐藏某个 ...

  4. python基础之内置装饰器

    装饰器 简介 功能与格式 内置装饰器 @classmethod @propertry @staticmethod 其它 ---------------------------------------- ...

  5. oracle使用日期

    当使用日期是,需要注意如果有超过5位小数加到日期上, 这个日期会进到下一天! 例如: 1. SELECT TO_DATE(‘01-JAN-93’+.99999) FROM DUAL; Returns: ...

  6. js保存图片到手机相册

    /保存到相册 function savePic(){ var picurl= $("#picurl").attr("src"); //alert(picurl) ...

  7. C# 递归、try

    一.递归 递归:在函数体内调用本函数自身,直到符合某一条件不再继续调用 两个需要满足的条件1.有反复调用自身函数的过程2.有函数的出口:有不再继续执行的条件 例子: 案例: (一).输入正整数n,求n ...

  8. Spring Cloud探路(三)REST 客户端Feign

    Declarative REST Client: Feign Feign is a declarative web service client. It makes writing web servi ...

  9. P1102 走迷宫二

    题目描述 大魔王抓住了爱丽丝,将她丢进了一口枯井中,并堵住了井口. 爱丽丝在井底发现了一张地图,他发现他现在身处一个迷宫当中,从地图中可以发现,迷宫是一个N*M的矩形,爱丽丝身处迷宫的左上角,唯一的出 ...

  10. linux 重用 short 为 I/O 内存

    short 例子模块, 在存取 I/O 端口前介绍的, 也能用来存取 I/O 内存. 为此, 你必须告 诉它使用 I/O 内存在加载时; 还有, 你需要改变基地址来使它指向你的 I/O 区. 例如, ...