1.CAS实现原子操作
compare and swap
原子指令直接使用处理器的原子指令
Atomic类
java为了解决原子性操作引入的工具类
cas指令执行失败后,会重新获取当前值,一直循环,直到成功
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!weakCompareAndSetInt(o, offset, v, v + delta));
return v;
}
1.1 CAS的ABA问题
线程1 执行将A变为C 线程2执行A变成C,C变成A,如果线程1在线程2执行完后再执行就会执行成功,这就是ABA问题;解决这个问题可以通过版本号来解决。
AtomicMarkableReference
这个解决了ABA问题只关心有没有被人改过
AtomicStampedReference
这个解决了ABA问题关心有没有被人改过,以及改过几次
1.2 循环时间长,开销大
大量线程高度竞争,CAS空挂占用的cpu时间多,反而导致
1.3 只能保证一个共享变量
AtomicReference封装成对象去实现多值的CAS
1.4 LongAdder
解决多个线程的写热点问题, 写冲突小的时候cas base,冲突多的时候,cas Cell数组;sum方法是一个估计值,不是准确值;sentinel 就使用了这个类
transient volatile long base;
transient volatile Cell[] cells;
public long sum() {
Cell[] cs = cells;
long sum = base;
if (cs != null) {
for (Cell c : cs)
if (c != null)
sum += c.value;
}
return sum;
}
2 线程安全性
2.1 线程封闭
栈封闭 尽量使用局部变量
ThreadLocal
无状态类 没有任何成员变量的类
类不可变
加锁和CAS
2.1 死锁和活锁
死锁与活锁区别是
死锁是处于 block状态,活锁是一直在获取锁释放锁处于 runnable;
活锁解决方法在释放锁后,休眠一个随机数,让一个线程拿到几把锁