前言
并发包的发展不是一蹴而就的,jdk1.4 以前并发工具比较有限,只有synchronized关键字、volatile、final等 jdk1.5 直接提供了一套相对完整的并发工具:java.util.concurrent jdk.17 进一步丰富了工具包,增加了Fork/join并发编程框架 jdk1.8 进一步扩充,以及优化了并发包的性能
组成
锁:提供适合各类场景的锁工具 原子变量:原子变量类,构建非阻塞算法的基础 并发框架:提供线程池相关类型 并发容器:提供一系列并发容器相关类型 同步工具:相对独立,且场景丰富的各类同步工具:信号量、闭锁、栅栏等
AtomicInteger
多线程情况下,对一个整型变量做加减操作时,如果不加任何的多线程并发控制。大概率时会出线程安全问题的。AtomicInteger 工具类,就是为简化整型变量的同步处理而诞生的
加:getAndAdd
递减:getAndDecrement
AtomicReference 原子引用
引用就是对象的别名,引用对象本身指向被引用对象,对引用对象的操作都会反映在被引用对象上。
设置值:boolean compareAndSet(value1,value2);返回值为true才是设置成功。
DoubleAdder
LongAccumulator
同步容器
ConcurrentHashMap:采用分段加锁,而非全局加锁的策略,增强了HashMap 非线程安全的特征,同时挺高并发度。
- 多线程下需要共同操作一个HashMap对象时,采用ConcurrentHashMap类型而不用做任何并发控制。
CopyOnWriteArrayList :多线程操作一个ArrayList时,为了线程安全需要对操作增加线程安全相关的锁控制。采用CopyOnWrite方式,可以做到读操作不用枷锁,而只需要对写操作加锁,且可以很方便的反馈写后的结果到读操作。
(注意:因为写时复制的原理本身,当存在大量写的时候,内存频繁复制原有数据的副本,如果数据量很大,很容易造成内存飙升和异常)
阻塞队列-BlockingQueue:可以适用于任何需要队列数据结构的场景,其次具有阻塞操作的特性,可用于线程之间的协同操作的场合。
并发框架
在JDK5开始,java将工作单元和执行机制做了分离,于是出现了Executor并行框架。 工作单元(任务),本质上就是需要运行的一段代码逻辑,但不管是啥逻辑的工作单元,最终都是需要运行在线程上的。
Executor 并行框架对工作单元、以及工作单元的执行做了高度抽象,形成一套完整的模型:
- 工作单元的抽象(任务) Runnable、Callable
- 任务的执行机制(如何组织任务的提交、如何管理提交的任务、如何组织多个线程执行) Executor、ExecutorService
- 对任务执行结果的抽象(如何跟踪任何任务执行状态、如何获取任务执行结果)Future、FutureTask
ForkJoin 并发框架 从JDK7开始,java提供了一套大任务分解小任务并行执行的框架,且在JDK8 做了进一步优化 Executor更适合做任务彼此之间无内在联系的场景,而ForkJoin更倾向于任务拆分并行执行的场合。
整个ForkJoin框架的核心接口和实现类:
- 线程池 ForkJoinPool :执行任务的线程池
- 执行线程ForkJoinWorkerThread :线程池中的一个执行任务线程
- 任务ForkJoinTask:运行在ForkJoinPool中的任务
场景:大数据集的处理(大文件、大表、内存中的大集合)
并发锁
-
ReentrantReadWriteLock
-
StampedLock是对ReentrantReadWriteLock的增强,ReentrantReadWriteLock是采用悲观锁的思想对数据修改的并发控制。
-
LockSupport 锁支持工具,可以在任何场合使用它阻塞线程和唤醒线程