为了解决常见的基本数据类型在并发编程的时候不受线程安全影响问题,提出了原子类的方案

原子类在解决了线程安全的同时,解决了互斥锁方案的加锁解锁的繁琐操作

无锁方案的实现

解决原子类的方案源于了硬件提供了CAS指令,(Compare And Swap)这个CPU指令提供了三个参数,共享变量的地址

比较的值B和新值C,只有A的值等于B,才能把A换为C,作为一条CPU指令,可以保证原子性

通过Java的代码实现可以简化为

class SimulatedCAS{

int count;

synchronized int cas(

int expect, int newValue){

// 读目前 count 的值

int curValue = count;

// 比较目前 count 值是否 == 期望值

if(curValue == expect){

// 如果是,则更新 count 的值

count = newValue;

}

// 返回写入前的值

return curValue;

}

}

Cas对于Count+=1来说,在A+1写入的时候,会拿着A来比较内存中的值,如果相等,才将A换为A+1,这就是CAS的语义

通常关于CAS指令来说,都会伴随着自旋,通常,实现一个线程安全的Count += 1 就利用了 while()指令,如果cas(count,newValue)返回的值不是count,就说明已经被更新过了,一直进行while,直到更新成功

由于是利用了CPU指令,所以这使用原子类性能会好很多

在Java中,使用CAS直接使用原子化 count =+ 1的内部流程为

//内部的流程如下,

//会循环调用 compareAndSwapLong(),并且会返回true和false

public final long getAndAddLong(

Object o, long offset, long delta){

long v;

do {

// 读取内存中的值

v = getLongVolatile(o, offset);

} while (!compareAndSwapLong(

o, offset, v, v + delta));

return v;

}

//原子性地将变量更新为x

//条件是内存中的值等于expected

//更新成功则返回true

native boolean compareAndSwapLong(

Object o, long offset,

long expected,

long x);

同样原子类中常见的CompareAndSet()也是返回的true或者false

原子类概述

JDK提供的原子类分为了

原子化的基本数据类型

原子化的对象引用类型

原子化数组

原子化对象属性更新器

原子化累加器

图片

基本属性中的原子类有

AtomicBoolean、AtomicInteger 和 AtomicLong

提供的方法有:

getAndIncrement() //原子化i++

getAndDecrement() //原子化的i–

incrementAndGet() //原子化的++i

decrementAndGet() //原子化的–i

//当前值+=delta,返回+=前的值

getAndAdd(delta)

//当前值+=delta,返回+=后的值

addAndGet(delta)

//CAS操作,返回是否成功

compareAndSet(expect, update)

//以下四个方法

//新值可以通过传入func函数来计算

getAndUpdate(func)

updateAndGet(func)

getAndAccumulate(x,func)

accumulateAndGet(x,func)

引用类型

AtomicReference、AtomicStampedReference 和 AtomicMarkableReference

对象的引用类型需要我们关注ABA问题 ,AtomicStampedReference 和 AtomicMarkableReference通过增加了版本号来解决了这个问题

AtomicStampedReference  通过一个版本号参数来实现的

AtomicMarkableReference  通过Boolean值来简化了版本号机制

原子化数组

AtomicIntegerArray、AtomicLongArray 和 AtomicReferenceArray

对应着

原子Int数组,原子Long数组,原子引用数组

只不过是增加了一个数组的索引参数

原子化的对象属性更新

AtomicIntegerFieldUpdater、AtomicLongFieldUpdater 和 AtomicReferenceFieldUpdater

原子化的更新对象的属性,都是通过反射方式的更新

但是要求对象的属性必须是volatile类型的,为了保证可见性

boolean compareAndSet(T obj, int expect, int update)

原子的累加器

DoubleAccumulator、DoubleAdder、LongAccumulator 和 LongAdder

发表评论

邮箱地址不会被公开。 必填项已用*标注