【Java 并发】【八】【Atomic】【一】JUC下的Atomic原子类体系概览
1 前言
这节我们就开始看看Atomic原子类系列,JUC包下提供的原子类底层的实现原理基本都是差不多的,都是基于volatile和CAS操作来保证线程安全的,我们后续会着重分析几个类。
2 概览
我们看下JUC下边都有哪些原子类:
看上面的图形,我们使用红色圈中的那些,就是我们要着重讨论的,一共分为一下几个类别:
(1)AtomicInteger、AtomicLong整型的原子类
如果我们在程序中使用了基本的Integer、Long等类型,进行基本的数学加减运算、赋值操作等。但是如果是在多线程环境下多个线程同时操作同一个Integer、Long变量,可能导致线程安全的问题。
要规避线程安全的问题,你可能需要用到锁,比如常用的synchronized、ReentrantLock锁等,让同一时间只有一个线程操作变量;但是锁是一个比较重的操作,可能导致线程获取不到锁而陷入沉睡,这样就会导致并发的性能降低。
然而如果你需要很高的并发性能,不想用锁,但需要是线程安全的;在这种情况下JUC就为我们提供了线程安全的原子类AtomicInteger、AtomicLong等,在多线程环境下进行加减运算、赋值操作等都是线程安全的。
AtomicInteger、AtomicLong使用非常广泛,比如你的系统里面可能用到一些统计、计数场景,比如每秒访问的流量、注册中心每秒接收到注册的次数、心跳的次数、可以使用这两个原子类。
在一些开源的分布式系统、中间件系统里面,大量的metric指标统计的功能都是基于AtomicInteger、AtomicLong这两个原子类去实现的,非常重要。
(2)AtomicBoolean 布尔类型的原子类
在多线程环境下我们使用基本的boolean、Boolean类型的布尔变量是非线程安全的,JUC提供类线程安全的布尔类型原子类AtomicBoolean。
AtmoicBoolean 通常使用的场景是一些状态标识,比如初始化标识、系统关闭标识、逻辑状态判断标识、状态开关等等。
此外AtomicBoolean 还经常使用做非常轻量级的锁,比如阿里开源的分布式消息中间件RocketMQ就使用了AtomicBoolean封装了一个自旋锁,具有非常高的并发性能。(CAS将AtomicBoolean设置成true表示获取到了锁,释放锁的时候CAS操作将AtomicBoolean设置为false)
(3)AtomicReference、AtomicStampReference可以封装对象的原子类
上面的提供的AtomicInteger、AtomicLong、AtomicBoolean等都是基本类型对应的原子类;但是如果你共享的是一个对象呢?多个线程同时修改一个对象呢?
在不使用锁的场景下可以将对象使用AtomicReference进行包装,然后CAS的去修改对象,也可以达到线程安全的效果。
AtomicStampReference 则是AtomicReference的升级版本,提供版本号机制,解决CAS中经典的ABA问题
(4)LongAdder原子类
是AtomicLong原子类的一个升级版本,在并发竞争非常激烈的时候可能会导致大量的线程CAS失败而不断自旋。
LongAdder采用分段锁的思想,在并发竞争非常激烈的时候使得不同的线程去竞争不同的锁;这样就可以减少对同一个锁的竞争,优化了并发的性能。
3 小结
这节我们大概看下原子类有哪些,以及我们接下来主要研究的几个,有理解不对的地方欢迎指正哈。