老王:小陈啊,从今天开始我们就要进入Atomic原子类系列的学习了,首先啊给你看一下JDK中提供给我们使用的原子类有哪些?
小陈:好啊,我记得JUC下面提供的原子类还是挺多的,所有的原子类的使用和底层实现的原理都全部要掌握吗?
老王:其实啊,JUC包下提供的原子类底层的实现原理基本都是差不多的,都是基于volatile和CAS操作来保证线程安全的,我们只需要掌握常用的一些原子类就可以了。
老王:至于这些原子类底层实现的原理,我们挑选几个比较有代表性的来讲,深入到源码级别,以及底层实现的细节;理解了我们讨论的这几个,你再去看其它的几个实现,发现都是一样的套路。
老王:哎呀,废话多了,不多说了,直接给你看下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问题
(5)LongAdder原子类
是AtomicLong原子类的一个升级版本,在并发竞争非常激烈的时候可能会导致大量的线程CAS失败而不断自旋,而LongAdder采用分段锁的思想,在并发竞争非常激烈的时候使得不同的线程去竞争不同的锁;这样就可以减少对同一个锁的竞争,优化了并发的性能。
小陈:哇塞,原子类还有这么多分类啊,厉害了...,老王啊,我们从哪里开始学,我等不及了,等我学完回去大展拳脚......
老王:小陈啊,我们本章的主题是概览,我们先大概了解一下Atomic的类体系、我们需要掌握哪些、分为哪些类等,具体的学习我们留到后面的讨论......
小陈:这样啊,那我先预习预习,明天等你来讲...
老王:好,本篇那就先到这里......
小陈:好的,我们下一章见。
关注小陈,公众号上更多更全的文章
JAVA并发文章目录(公众号)
JAVA并发专题 《筑基篇》
1.什么是CPU多级缓存模型?
2.什么是JAVA内存模型?
3.线程安全之可见性、有序性、原子性是什么?
4.什么是MESI缓存一致性协议?怎么解决并发的可见性问题?
JAVA并发专题《练气篇》
5.volatile怎么保证可见性?
6.什么是内存屏障?具有什么作用?
7.volatile怎么通过内存屏障保证可见性和有序性?
8.volatile为啥不能保证原子性?
9.synchronized是个啥东西?应该怎么使用?
10.synchronized底层之monitor、对象头、Mark Word?
11.synchronized底层是怎么通过monitor进行加锁的?
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
13.synchronized怎么保证可见性、有序性、原子性?
JAVA并发专题《结丹篇》
14. JDK底层Unsafe类是个啥东西?
15.unsafe类的CAS是怎么保证原子性的?
16.Atomic原子类体系讲解
17.AtomicInteger、AtomicBoolean的底层原理
18.AtomicReference、AtomicStampReference底层原理
19.Atomic中的LongAdder底层原理之分段锁机制
20.Atmoic系列Strimped64分段锁底层实现源码剖析
JAVA并发专题《金丹篇》
21.AQS是个啥?为啥说它是JAVA并发工具基础框架?
22.基于AQS的互斥锁底层源码深度剖析
23.基于AQS的共享锁底层源码深度剖析
24.ReentrantLock是怎么基于AQS实现独占锁的?
25.ReentrantLock的Condition机制底层源码剖析
26.CountDownLatch 门栓底层源码和实现机制深度剖析
27.CyclicBarrier 栅栏底层源码和实现机制深度剖析
28.Semaphore 信号量底层源码和实现机深度剖析
29.ReentrantReadWriteLock 读写锁怎么表示?
30. ReentrantReadWriteLock 读写锁底层源码和机制深度剖析
JAVA并发专题《元神篇》并发数据结构篇
31.CopyOnAarrayList 底层分析,怎么通过写时复制副本,提升并发性能?
32.ConcurrentLinkedQueue 底层分析,CAS 无锁化操作提升并发性能?
33.ConcurrentHashMap详解,底层怎么通过分段锁提升并发性能?
34.LinkedBlockedQueue 阻塞队列怎么通过ReentrantLock和Condition实现?
35.ArrayBlockedQueued 阻塞队列实现思路竟然和LinkedBlockedQueue一样?
36.DelayQueue 底层源码剖析,延时队列怎么实现?
37.SynchronousQueue底层原理解析
JAVA并发专题《飞升篇》线程池底层深度剖析
38. 什么是线程池?看看JDK提供了哪些默认的线程池?底层竟然都是基于ThreadPoolExecutor的?
39.ThreadPoolExecutor 构造函数有哪些参数?这些参数分别表示什么意思?
40.内部有哪些变量,怎么表示线程池状态和线程数,看看道格.李大神是怎么设计的?
41. ThreadPoolExecutor execute执行流程?怎么进行任务提交的?addWorker方法干了啥?什么是workder?
42. ThreadPoolExecutor execute执行流程?何时将任务提交到阻塞队列? 阻塞队列满会发生什么?
43. ThreadPoolExecutor 中的Worker是如何执行提交到线程池的任务的?多余Worker怎么在超出空闲时间后被干掉的?
44. ThreadPoolExecutor shutdown、shutdownNow内部核心流程
45. 再回头看看为啥不推荐Executors提供几种线程池?
46. ThreadPoolExecutor线程池篇总结