线程安全分为三种特性:
- 原子性:提供了互斥访问,同一时刻只能有一个线程来对它进行操作
- 可见性:一个线程对主内存的修改可以及时的被其他线程观察到
- 有序性:一个线程观察其他线程中的指令执行顺序,由于指令 重排序 的存在,该观察结果一般杂乱无序
我们这里讲解一下原子性-Atomic包
(1)AtomicInteger
例:
//定义实例对象
private static AtomicInteger count = new AtomicInteger(0);
//先增加操作再获取当前值
count.incrementAndGet();
incrementAndGet源码中 o是当前对象,offset是 当前操作的首个值,delta是第二个值。如1+2=3,首值1。V是调用底层方法得到的值:如3。
期望值和底层值相同时才执行v+delta。
此为CAS的实现:当前值和底层值对比,如果不一样会不停的选,如果相同会返回数值。
工作内存(当前值)和主内存(底层)之间的差异导致此行为。
AtomicInteger的机制是在一个死循环内不断地尝试修改目标值,直到修改成功。如果竞争不激烈的时候修改成功的机率很高;反之,多次尝试导致性能受到影响。
(2)LongAdder相较于AtomicLong
优点:将单点的更新压力分散到各个节点上,在低并发的时候通过对base的直接更新,可以很好的保障和atomic的性能基本一致;在高并发时将压力分散。
缺点:在同期时如果有并发更新,可能会导致统计的数据有些误差。
LongAdder适用一般线程竞争高,数据误差要求不高
AtomicLong适用线程竞争低,数据误差要求高
(3)AtomicIntegerFieldUpdater可进行原子性修改,更新指定类上某一字段的值,要求字段必须用volataile等修饰。
(4)AtomicStampReference:CAS的ABA问题(在进行CAS操作时,将变量A改为B,但又改为A。每次更新时版本号加一。)