一、原子类
原子类同锁类似,都是为了保证并发安全,但它相对于锁的优势:
- 粒度更细
- 效率更高
1.1 基本类型原子类
用法:
1.2 引用类型原子类
1.3 把普通变量升级为原子功能
public class AtomicIntegerFieldUpdaterDemo implements Runnable {
static Candidate tom;
static Candidate peter;
public static AtomicIntegerFieldUpdater<Candidate> scoreUpdater =
AtomicIntegerFieldUpdater.newUpdater(Candidate.class, "score");
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
peter.score++;
scoreUpdater.getAndIncrement(tom);
}
}
public static class Candidate {
volatile int score;
}
public static void main(String[] args) throws InterruptedException {
tom = new Candidate();
peter = new Candidate();
AtomicIntegerFieldUpdaterDemo r = new AtomicIntegerFieldUpdaterDemo();
Thread thread1 = new Thread(r);
Thread thread2 = new Thread(r);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("普通变量"+peter.score);
System.out.println("升级后的"+tom.score);
}
}
1.4 Adder累加器
累加器有两种:LongAdder、AtomicLong
LongAdder的性能比AtomicLong的性能要高。
- AtomicLong原理:每个线程在加完之后,都会强制的刷回主存,保证可见性,这样做虽然可以避免并发危险,但是会极大的影响效率。
- LongAdder:每个线程都有自己的一个计数器,不会和其他线程计数器干扰
LongAdder一如了分段累加的概念,内部有一个base变量和一个Cell[]数组共同参与计数:- base变量:竞争不激烈,直接累加到该变量上
- Cell[]数组:竞争激烈,各个线程分散累加到自己的槽Cell[i]中
由于sum没有加锁,可能导致数据出错。
二、CAS
2.1 CAS原理
2.2 CAS缺点
- ABA问题:一个数据改了一次后,又改回原来的值
解决方法:加版本号 - 自旋时间过长
由于CAS失败后会进行重试,会导致开销大