Java并发编程-原子类总结
为了更好地支持原子性操作,并在同时规避使用synchronized关键字带来的系统开销(线程上下文切换),JUC中提供了一些原子操作类。原子操作类主要依赖cas与volatile关键字实现线程安全。
本文仅对常见的原子操作类进行罗列,并提及一些类的特点(面试高频考点),会长期进行更新和完善。
原子操作类的分类
基本数据类型相关:
AtomicBoolean
AtomicInteger
AtomicLong
引用类型相关:
AtomicReference
AtomicStampedReference
AtomicMarkableReference
数组相关:
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
字段(Field)相关:
AtomicReferenceFieldUpdater
AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
原子累加器:
LongAdder
DoubleAdder
基本数据类型相关
主要是操作数值类型的对象,没有什么特殊的地方,需要知道一些常用的方法,如getAndIcrement()
、incrementAndGet()
、get()
等。
引用类型相关
AtomicStampedReference
用于解决ABA问题,该类在维护数据本身的同时,还维护了数据的版本号,来确保期望值与工作内存中的值的版本是一致的,可以知道中途这个值被改了几次,中途没有别的线程修改过这个对象。
AtomicMarkableReference
也可用于解决ABA问题,但是它只关心对象的状态(True Or False)是否符合预期,而不维护一个对象版本号(不关心对象被改了几次),只要状态一致就可以对目标对象进行设置。
字段更新器
利用字段更新器,可以针对对象的某个域(Field)进行原子操作,只能配合 volatile 修饰的字段使用,否则会出现异常。
原子累加器
LongAdder
采用多个累加单元(Cell)进行数值的累加,每个线程对一个base变量进行累加,最后将所有线程得出的结果进行整合,这种方式使得每个线程操作的目标对象都不同,减少了cas重试失败的次数,提高了性能,因此它比使用普通原子操作类AtomicLong
更快,更高效。
优势
cas+volatile的无锁线程安全,在多核场景下的效率高于synchronized关键字,主要原因在于避免了线程上下文切换。
缺点
cas和volatile实现的线程安全,只有在多核CPU的条件下才能发挥优势。单核情况下,通过CompareAndSet进行数据更新的形式,原地自旋并不会降低系统开销,反而浪费了这部分资源。