原子类适用于需要原子操作而有需要减少资源消耗时 , 原子类相当于 volatile 和 CAS 的工具类 .
基本类型 : 使用原子的方式更新基本类型
数组类型 : 使用原子的方式更新数组里的某个元素
引用类型
对象的属性修改类型
原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 contextswitch切换到另一个线程 , 之所以称为原子变量,是因为其包含一些以原子方式实现组合操作的方法
回顾 CAS : CAS的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值
原子类主要通过 CAS (compare and swap) + volatile 和 native 方法来保证原子操作 !
// 案例 : AtomicInteger
// 它的主要内部成员是:
private volatile int value;
注意,它的声明带有volatile,这是必需的,以保证内存可见性。
// 它的大部分更新方法实现都类似,我们看一个方法incrementAndGet,其代码为:
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
// 重点 :
1 . value 是一个volatile变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值
2 . UnSafe 类的objectFieldOffset()方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址 返回值是 valueOffset
我们从源码看看那些之前被我们忽略的东西 , 此类可以代表大多数基本类型
// Node 1 : 原子类支持序列化
implements java.io.Serializable
---------------------->
// Node 2 : CAS 对象 Unsafe , Unsafe 之前已经说过了, 其中有很多 Native 犯法
private static final Unsafe unsafe = Unsafe.getUnsafe();
---------------------->
// Node 3 : 偏移量 valueOffset
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
// objectFieldOffset() : 获取某个字段相对Java对象的“起始地址”的偏移量 , 后续通过便宜量获取方法
// getDeclaredField() : 返回一个字段对象,该对象反映由这个类对象表示的类或接口的指定声明字段
---------------------->
// Node 4 : 核心值 Value ,可以看到 value 使用 volatile 进行修饰
private volatile int value;
---------------------->
// Node 5 : 操作方法 , 可以看到 valueOffset 此时已经发挥了作用
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
---------------------->
// Node 6 : 值转换 , AtomicInteger 提供了以下四个值得固有转换方法
public int intValue() ;
public long longValue() ;
public float floatValue();
public double doubleValue();
现在看一下 AtomicReference 有什么特别之处
// Node 1 : 不再继承 Number 接口
// Node 2 : 使用泛型方法
public class AtomicReference<V> implements java.io.Serializable
private volatile V value;
// Node 3 : 比对时使用 putOrderedObject
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
相对而言 AtomicIntegerArray 有更多得变化 , 其他的大同小异
// Node 1 : 对数组元素偏移进行了记录 , 此处不再是 "value" 偏移
private static final int base = unsafe.arrayBaseOffset(int[].class);
private static final int shift;
private final int[] array;
// Node 2 : 比较使用了 getAndSetInt
unsafe.getAndSetInt(array, checkedByteOffset(i), newValue)
AtomicInteger integer = new AtomicInteger();
logger.info("------> 1 > 获取原子变量 :[{}] <-------", integer.get());
// Step 2 : 设置参数
integer.set(999);
logger.info("------> 2 > 获取原子变量 :[{}] <-------", integer.get());
logger.info("------> 失败比较获取 : 测试比较判断 :[{}] <-------", integer.compareAndSet(0, 998));
logger.info("------> 3 > 获取原子变量 :[{}] <-------", integer.get());
logger.info("------> 成功比较获取 : 测试比较判断 :[{}] <-------", integer.compareAndSet(999, 998));
logger.info("------> 4 > 获取原子变量 :[{}] <-------", integer.get());
// Step 3 : 获取当前的值,并设置新的值
logger.info("------> 测试比较判断 :[{}] <-------", integer.getAndSet(888));
logger.info("------> 5 > 获取原子变量 :[{}] <-------", integer.get());
// Step 4 : 获取当前的值,并设置新的值
logger.info("------> 测试比较判断 :[{}] <-------", integer.getAndIncrement());
logger.info("------> 6 > 获取原子变量 :[{}] <-------", integer.get());
// 以原子方式给当前值加1并获取新值
logger.info("------> 测试比较判断 :[{}] <-------", integer.incrementAndGet());
logger.info("------> 6-1 > 获取原子变量 :[{}] <-------", integer.get());
// Step 5 : 获取当前的值,并设置新的值
logger.info("------> 测试比较判断 :[{}] <-------", integer.getAndDecrement());
logger.info("------> 7 > 获取原子变量 :[{}] <-------", integer.get());
// 以原子方式给当前值减1并获取新值
logger.info("------> 测试比较判断 :[{}] <-------", integer.decrementAndGet());
logger.info("------> 7 > 获取原子变量 :[{}] <-------", integer.get());
// Step 6 : 获取当前的值,并设置新的值
logger.info("------> 测试比较判断 :[{}] <-------", integer.getAndAdd(99));
logger.info("------> 8 > 获取原子变量 :[{}] <-------", integer.get());
// 以原子方式给当前值加delta并获取新值
logger.info("------> 测试比较判断 :[{}] <-------", integer.addAndGet(99));
logger.info("------> 8 > 获取原子变量 :[{}] <-------", integer.get());
}
/**
* 测多线程方式
*/
public void testThead() throws Exception {
InnerTO innerTO = new InnerTO();
MyThread[] threadDSS = new MyThread[1000];
for (int i = 0; i < 1000; i++) {
threadDSS[i] = new MyThread(innerTO);
}
for (int i = 0; i < 1000; i++) {
threadDSS[i].start();
}
logger.info("------> 原子类线程 Start 完成 :{} <-------", innerTO.getInteger().get());
for (int i = 0; i < 1000; i++) {
if (i % 100 == 0) {
Thread.sleep(1);
logger.info("------> 测试原子类 :{} <-------", innerTO.getInteger().get());
}
}
}
/**
* 包含原子类的对象
*
**/
class InnerTO {
AtomicInteger integer = new AtomicInteger();
public AtomicInteger getInteger() {
return integer;
}
public void setInteger(AtomicInteger integer) {
this.integer = integer;
}
}
/**
* 运行线程类
*
**/
class MyThread extends Thread {
public InnerTO innerTO = new InnerTO();
public MyThread(InnerTO innerTO) {
this.innerTO = innerTO;
}
@Override
public void run() {
int i = innerTO.getInteger().getAndIncrement();
if (i == 999) {
logger.info("------> 线程执行完成 <-------");
}
}
}
// 可以看到在没有锁的情况下 ,数据保证了原子性
------> 原子类线程 Start 完成 :876 <-------
------> 测试原子类 :918 <-------
------> 测试原子类 :950 <-------
------> 测试原子类 :973 <-------
------> 测试原子类 :989 <-------
------> 线程执行完成 <-------
------> 测试原子类 :1000 <-------
------> 测试原子类 :1000 <-------
------> 测试原子类 :1000 <-------
------> 测试原子类 :1000 <-------
------> 测试原子类 :1000 <-------
------> 测试原子类 :1000 <-------
[芋道源码](http://www.iocoder.cn/JUC/sike/aqs-3/)
[死磕系列](http://cmsblogs.com/?cat=151)
阅读量:2015
点赞量:0
收藏量:0