一、CAS
1、CAS简介
- CAS(compare and swap),比较并交换。
- CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。
- 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。
- 通过CAS可以实现原子操作
2、ABA问题
- 如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际变化了。
- ABA问题可以通过添加版本号来解决:1A-2B-3A。
3、乐观锁、悲观锁
- 乐观锁认为每次修改数据时不会有人同时修改数据。执行更新时判断在此期间是否有人修改了数据,如果数据发生变动则放弃此次更新,否则执行更新。
- 悲观锁认为每次修改数据时都会有人同时修改数据。执行更新时锁住数据,不允许其他人更新。
- CAS属于乐观锁,Synchronized属于悲观锁。
4、CAS效率

从图中可以看出:
在单核系统中,CAS省去了锁升级、抢锁等过程;
在多核系统中,传统加锁会导致只有一条线程在执行任务,而CAS则可以多线程同时执行任务,提升效率。
注意:如果线程竞争比较大,由于其他线程更新失败,CAS会一直重试,导致CPU一直执行重复任务,浪费CPU资源,此时使用锁可能是个更好的选择。
二、原子变量
基于CAS操作,Java提供了一套API,在java.util.concurrent.atomic包下。常用的如:AtomicInteger、AtomicLong、AtomicBoolean等。原子变量是线程安全的。
AtomicInteger atomicInteger = new AtomicInteger(1);
// 以AtomicInteger为例,i++可以写成如下代码
atomicInteger.incrementAndGet();
分析一下AtomicInteger源码:
public class AtomicInteger extends Number implements java.io.Serializable {
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
// volatile修饰
private volatile int value;
public final int incrementAndGet() {
return U.getAndAddInt(this, VALUE, 1) + 1;
}
}
可以看到:
1、AtomicInteger中的value被volatile修饰,保证了可见性;
2、incrementAndGet通过Unsafe.getAndAddInt实现。
public class Unsafe {
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
//重新获取var5的值
var5 = this.getIntVolatile(var1, var2);
// 如果CAS更新失败,重复do中的代码
} while (!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
// expected:期望值,update:目标值
public final native boolean compareAndSwapInt(Object o, long offset, int expected,int update);
}
再看Unsafe的源码,getAndAddInt中,会通过CAS操作尝试更新,若更新失败,则会一直重试。
三、原子累加器
为了对多线程下大量自增操作进行优化,Java还提供了原子累加器:LongAdder。

伪共享问题
CPU为了效率,每次会将内存中的数据读取到高速缓冲区,高速缓冲区中的最小缓存单位是Cache Line,一般是64byte,一个long类型是8byte,因此一个缓存行可以存储8个long类型的变量。
于是可能出现如下问题:
1、我们想core1处理cell[0]的数据,core2处理cell[1]的数据;
2、由于读取了一行数据,导致core1、core2同时有cell[0]、cell[1]的数据;
3、因此当core1更新了cell[0]时,core2也需要从内存中重新读取数据,来保证数据的一致性。
当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享。
解决方法:java8提供@sun.misc.Contended注解
// LongAdder中的Cell便是使用@sun.misc.Contended注解来解决伪共享问题
@sun.misc.Contended static final class Cell {}

网友评论