共计 7729 个字符,预计需要花费 20 分钟才能阅读完成。
上篇文章为解决多线程中呈现的同步问题引入了锁的概念,上篇文章介绍的是 Synchronized 关键字锁,本篇文章介绍更加轻量级的锁 Lock 接口及引出 JUC 的相干常识。
本文不力争阐释分明 JUC 框架的所有内容,而是站在肯定的高度下,理解 Juc 下包的设计与实现。
[TOC]
一、LOCK 锁概述
实现同步的另外一种形式是 Lock 锁。
Lock 锁是一个接口,其所有的实现类为:
- ReentrantLock(可重入锁)
- ReentrantReadWriteLock.ReadLock(可重入读写锁中的读锁)
- ReentrantReadWriteLock.WriteLock(可重入读写锁中的写锁)
与 synchronized 不同的是,应用 LOCK 锁与其有六个区别
1 synchronized 是 Java 内置关键字,Lock 是一个接口
2 synchronized 无奈判断是否获取锁,Lock 能够判断是否获取锁
3 synchronized 能够主动开释锁,Lock 必须手动开释锁,如果不开释就会造成死锁
4 同一个锁对象,线程 A synchronized 获取之后,线程 B 只能期待,造成阻塞,Lock 并不会期待
5 synchronized 可重入锁,不可中断,非偏心锁,Lock 可重入锁,能够判断,非偏心锁(可设置)6 synchronized 适宜大量同步代码,Lock 适宜大量同步代码
Lock 接口位于 java.util.concurrent.locks 包下,在父级的包下有两个包。
- java.util.concurrent:包下次要是包含并发相干的接口与类,阻塞队列、线程池等,外面蕴含 59 个类或者接口
- java.util.concurrent.atomic:该包下次要包含原子性操作相干的类,比方罕用的 AtomicInteger、AtomicBoolean、AtomicIntegerArry 等,外面蕴含 18 个类或者接口
其中父级的包 java.util .concurrent 波及到 Java 多线程最重要的一部分——JUC 编程。
二、JUC 概述
JUC 就是 java.util .concurrent 工具包的简称。这是一个解决线程的工具包,JDK 1.5 开始呈现的, 在此包中减少了在并发编程中很罕用的工具类。
用于定义相似于线程的自定义子系统, 包含线程池, 异步 IO 和轻量工作框架;
还提供了设计用于多线程上下文中的 Collection 实现等;
下图为 JUC 波及到的所有知识点。
JUC 应该包含五个局部的内容。
1、Lock 框架
① 接口: Condition
Condition 为接口类型,它将 Object 监视器办法 (wait、notify 和 notifyAll) 分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合应用,为每个对象提供多个期待 set (wait-set)。其中,Lock 代替了 synchronized 办法和语句的应用,Condition 代替了 Object 监视器办法的应用。能够通过 await(),signal()来休眠 / 唤醒线程。
②接口: Lock
Lock 为接口类型,Lock 实现提供了比应用 synchronized 办法和语句可取得的更宽泛的锁定操作。此实现容许更灵便的构造,能够具备差异很大的属性,能够反对多个相干的 Condition 对象。
③接口: ReadWriteLock
ReadWriteLock 为接口类型,保护了一对相干的锁,一个用于只读操作,另一个用于写入操作。只有没有 writer,读取锁能够由多个 reader 线程同时放弃。写入锁是独占的。
④抽象类: AbstractOwnableSynchonizer
AbstractOwnableSynchonizer 为抽象类,能够由线程以独占形式领有的同步器。此类为创立锁和相干同步器 (随同着所有权的概念) 提供了根底。AbstractOwnableSynchronizer 类自身不治理或应用此信息。然而,子类和工具能够应用适当保护的值帮忙管制和监督拜访以及提供诊断。
⑤抽象类(long): AbstractQueuedLongSynchronizer
AbstractQueuedLongSynchronizer 为抽象类,以 long 模式保护同步状态的一个 AbstractQueuedSynchronizer 版本。此类具备的构造、属性和办法与 AbstractQueuedSynchronizer 完全相同,但所有与状态相干的参数和后果都定义为 long 而不是 int。当创立须要 64 位状态的多级别锁和屏障等同步器时,此类很有用。
⑥ 外围抽象类(int): AbstractQueuedSynchonizer
AbstractQueuedSynchonizer 为抽象类,其为实现依赖于先进先出 (FIFO) 期待队列的阻塞锁和相干同步器 (信号量、事件,等等) 提供一个框架。此类的设计指标是成为依附单个原子 int 值来示意状态的大多数同步器的一个有用根底。
⑦锁罕用类: LockSupport
LockSupport 为罕用类,用来创立锁和其余同步类的根本线程阻塞原语。LockSupport 的性能和 ”Thread 中的 Thread.suspend()和 Thread.resume()有点相似 ”,LockSupport 中的 park() 和 unpark() 的作用别离是阻塞线程和解除阻塞线程。然而 park()和 unpark()不会遇到“Thread.suspend 和 Thread.resume 所可能引发的死锁”问题。
⑧锁罕用类: ReentrantLock
ReentrantLock 为罕用类,它是一个可重入的互斥锁 Lock,它具备与应用 synchronized 办法和语句所拜访的隐式监视器锁雷同的一些根本行为和语义,但性能更弱小。
⑨锁罕用类: ReentrantReadWriteLock
ReentrantReadWriteLock 是读写锁接口 ReadWriteLock 的实现类,它包含 Lock 子类 ReadLock 和 WriteLock。ReadLock 是共享锁,WriteLock 是独占锁。
⑩锁罕用类: StampedLock
它是 java8 在 java.util.concurrent.locks 新增的一个 API。StampedLock 管制锁有三种模式(写,读,乐观读),一个 StampedLock 状态是由版本和模式两个局部组成,锁获取办法返回一个数字作为票据 stamp,它用相应的锁状态示意并管制拜访,数字 0 示意没有写锁被受权拜访。在读锁上分为乐观锁和乐观锁。
2、Tools 类
①工具罕用类: CountDownLatch
CountDownLatch 为罕用类,它是一个同步辅助类,在实现一组正在其余线程中执行的操作之前,它容许一个或多个线程始终期待。
②具罕用类: CyclicBarrier
CyclicBarrier 为罕用类,其是一个同步辅助类,它容许一组线程相互期待,直到达到某个公共屏障点 (common barrier point)。在波及一组固定大小的线程的程序中,这些线程必须不断地相互期待,此时 CyclicBarrier 很有用。因为该 barrier 在开释期待线程后能够重用,所以称它为循环 的 barrier。)
③工具罕用类: Phaser
Phaser 是 JDK 7 新增的一个同步辅助类,它能够实现 CyclicBarrier 和 CountDownLatch 相似的性能,而且它反对对工作的动静调整,并反对分层构造来达到更高的吞吐量。
④ 工具罕用类: Semaphore
Semaphore 为罕用类,其是一个计数信号量,从概念上讲,信号量保护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),而后再获取该许可。每个 release() 增加一个许可,从而可能开释一个正在阻塞的获取者。然而,不应用理论的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的口头。通常用于限度能够拜访某些资源 (物理或逻辑的) 的线程数目。
⑤工具罕用类: Exchanger
Exchanger 是用于线程合作的工具类, 次要用于两个线程之间的数据交换。它提供一个同步点,在这个同步点,两个线程能够替换彼此的数据。这两个线程通过 exchange()办法替换数据,当一个线程先执行 exchange()办法后,它会始终期待第二个线程也执行 exchange()办法,当这两个线程达到同步点时,这两个线程就能够替换数据了。
3、Collections: 并发汇合
并发汇合的类构造关系
①Queue: ArrayBlockingQueue
一个由数组反对的有界阻塞队列。此队列按 FIFO(先进先出)准则对元素进行排序。队列的头部 是在队列中存在工夫最长的元素。队列的尾部 是在队列中存在工夫最短的元素。新元素插入到队列的尾部,队列获取操作则是从队列头部开始取得元素。
②Queue: LinkedBlockingQueue
一个基于已链接节点的、范畴任意的 blocking queue。此队列按 FIFO(先进先出)排序元素。队列的头部 是在队列中工夫最长的元素。队列的尾部 是在队列中工夫最短的元素。新元素插入到队列的尾部,并且队列获取操作会取得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列,然而在大多数并发应用程序中,其可预知的性能要低。
③Queue: LinkedBlockingDeque
一个基于已链接节点的、任选范畴的阻塞双端队列。
④Queue: ConcurrentLinkedQueue
一个基于链接节点的无界限程平安队列。此队列依照 FIFO(先进先出)准则对元素进行排序。队列的头部 是队列中工夫最长的元素。队列的尾部 是队列中工夫最短的元素。新的元素插入到队列的尾部,队列获取操作从队列头部取得元素。当多个线程共享拜访一个公共 collection 时,ConcurrentLinkedQueue 是一个失当的抉择。此队列不容许应用 null 元素。
⑤ Queue: ConcurrentLinkedDeque
是双向链表实现的无界队列,该队列同时反对 FIFO 和 FILO 两种操作形式。
⑥ Queue: DelayQueue
延时无界阻塞队列,应用 Lock 机制实现并发拜访。队列里只容许放能够“延期”的元素,队列中的 head 是最先“到期”的元素。如果队里中没有元素到“到期”,那么就算队列中有元素也不能获取到。
⑦ Queue: PriorityBlockingQueue
无界优先级阻塞队列,应用 Lock 机制实现并发拜访。priorityQueue 的线程平安版,不容许寄存 null 值,依赖于 comparable 的排序,不容许寄存不可比拟的对象类型。
⑧Queue: SynchronousQueue
没有容量的同步队列,通过 CAS 实现并发拜访,反对 FIFO 和 FILO。
⑨Queue: LinkedTransferQueue
JDK 7 新增,单向链表实现的无界阻塞队列,通过 CAS 实现并发拜访,队列元素应用 FIFO(先进先出)形式。LinkedTransferQueue 能够说是 ConcurrentLinkedQueue、SynchronousQueue(偏心模式)和 LinkedBlockingQueue 的超集, 它不仅仅综合了这几个类的性能,同时也提供了更高效的实现。
⑩List: CopyOnWriteArrayList
ArrayList 的一个线程平安的变体,其中所有可变操作 (add、set 等等) 都是通过对底层数组进行一次新的复制来实现的。这个别须要很大的开销,然而当遍历操作的数量大大超过可变操作的数量时,这种办法可能比其余代替办法更 无效。在不能或不想进行同步遍历,但又须要从并发线程中排除抵触时,它也很有用。
⑩①Set: CopyOnWriteArraySet
对其所有操作应用外部 CopyOnWriteArrayList 的 Set。行将所有操作转发至 CopyOnWriteArayList 来进行操作,可能保障线程平安。在 add 时,会调用 addIfAbsent,因为每次 add 时都要进行数组遍历,因而性能会略低于 CopyOnWriteArrayList。
⑩②Set: ConcurrentSkipListSet
一个基于 ConcurrentSkipListMap 的可缩放并发 NavigableSet 实现。set 的元素能够依据它们的天然程序进行排序,也能够依据创立 set 时所提供的 Comparator 进行排序,具体取决于应用的构造方法。
⑩③ Map: ConcurrentHashMap
是线程平安 HashMap 的。ConcurrentHashMap 在 JDK 7 之前是通过 Lock 和 segment(分段锁)实现,JDK 8 之后改为 CAS+synchronized 来保障并发平安。
详细分析请看: [JUC 并发汇合: ConcurrentHashMap 详解](), 蕴含了对 JDK 7 和 JDK 8 版本的源码剖析。
⑩④ Map: ConcurrentSkipListMap
线程平安的有序的哈希表(相当于线程平安的 TreeMap); 映射能够依据键的天然程序进行排序,也能够依据创立映射时所提供的 Comparator 进行排序,具体取决于应用的构造方法。
4、Atomic: 原子类
其根本的个性就是在多线程环境下,当有多个线程同时执行这些类的实例蕴含的办法时,具备排他性,即当某个线程进入办法,执行其中的指令时,不会被其余线程打断,而别的线程就像自旋锁一样,始终等到该办法执行实现,才由 JVM 从期待队列中抉择一个另一个线程进入,这只是一种逻辑上的了解。
实际上是借助硬件的相干指令来实现的,不会阻塞线程(或者说只是在硬件级别上阻塞了)。
①根底类型:AtomicBoolean,AtomicInteger,AtomicLong
AtomicBoolean,AtomicInteger,AtomicLong 是相似的,别离针对 bool,interger,long 的原子类。
②数组:AtomicIntegerArray,AtomicLongArray,BooleanArray
AtomicIntegerArray,AtomicLongArray,AtomicBooleanArray 是数组原子类。
③援用:AtomicReference,AtomicMarkedReference,AtomicStampedReference
AtomicReference,AtomicMarkedReference,AtomicStampedReference 是援用相干的原子类。
④FieldUpdater:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater
AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater 是 FieldUpdater 原子类。
5、Executors: 线程池
线程池类构造关系
①接口: Executor
Executor 接口提供一种将工作提交与每个工作将如何运行的机制 (包含线程应用的细节、调度等) 拆散开来的办法。通常应用 Executor 而不是显式地创立线程。
② ExecutorService
ExecutorService 继承自 Executor 接口,ExecutorService 提供了治理终止的办法,以及可为跟踪一个或多个异步工作执行情况而生成 Future 的办法。能够敞开 ExecutorService,这将导致其进行承受新工作。敞开后,执行程序将最初终止,这时没有工作在执行,也没有工作在期待执行,并且无奈提交新工作。
③ScheduledExecutorService
ScheduledExecutorService 继承自 ExecutorService 接口,可安顿在给定的提早后运行或定期执行的命令。
④AbstractExecutorService
AbstractExecutorService 继承自 ExecutorService 接口,其提供 ExecutorService 执行办法的默认实现。此类应用 newTaskFor 返回的 RunnableFuture 实现 submit、invokeAny 和 invokeAll 办法,默认状况下,RunnableFuture 是此包中提供的 FutureTask 类。
⑤FutureTask
FutureTask 为 Future 提供了根底实现,如获取工作执行后果 (get) 和勾销工作 (cancel) 等。如果工作尚未实现,获取工作执行后果时将会阻塞。一旦执行完结,工作就不能被重启或勾销(除非应用 runAndReset 执行计算)。FutureTask 罕用来封装 Callable 和 Runnable,也能够作为一个工作提交到线程池中执行。除了作为一个独立的类之外,此类也提供了一些功能性函数供咱们创立自定义 task 类应用。FutureTask 的线程平安由 CAS 来保障。
⑥ 外围: ThreadPoolExecutor
ThreadPoolExecutor 实现了 AbstractExecutorService 接口,也是一个 ExecutorService,它应用可能的几个池线程之一执行每个提交的工作,通常应用 Executors 工厂办法配置。线程池能够解决两个不同问题: 因为缩小了每个工作调用的开销,它们通常能够在执行大量异步工作时提供加强的性能,并且还能够提供绑定和治理资源 (包含执行工作集时应用的线程) 的办法。每个 ThreadPoolExecutor 还保护着一些根本的统计数据,如实现的工作数。
⑦外围: ScheduledThreadExecutor
ScheduledThreadPoolExecutor 实现 ScheduledExecutorService 接口,可安顿在给定的提早后运行命令,或者定期执行命令。须要多个辅助线程时,或者要求 ThreadPoolExecutor 具备额定的灵活性或性能时,此类要优于 Timer。)
⑧外围: Fork/Join 框架
ForkJoinPool 是 JDK 7 退出的一个线程池类。Fork/Join 技术是分治算法 (Divide-and-Conquer) 的并行实现,它是一项能够取得良好的并行性能的简略且高效的设计技术。目标是为了帮忙咱们更好地利用多处理器带来的益处,应用所有可用的运算能力来晋升利用的性能。)
⑨工具类: Executors
Executors 是一个工具类,用其能够创立 ExecutorService、ScheduledExecutorService、ThreadFactory、Callable 等对象。它的应用融入到了 ThreadPoolExecutor, ScheduledThreadExecutor 和 ForkJoinPool 中。
通过以上的章节咱们不难看出,JUC 体系的内容也是十分宏大的,通过这篇文章能对 JUC 的整个体系能有所理解咱们的目标就达到了。
接下来的文章会明显别类的对这些类和接口进行具体的论述剖析。