剑指Offer(类库)——JUC包的知识梳理
首先来展示一张JUC包下包与类的框图
其中,JUC下共有这么几个大包:
- 线程执行器executor
- 锁locks
- 原子变量类atomic
- 并发工具类tools
- 并发集合collections
针对上面几个JUC的大包,之前已经介绍过了一部分的并发集合和Executor线程执行类了。
下面对其他几个包进行一下概述:
1. Tools
首先我们来看看并发工具类Tools,主要提一些面试中经常会问到的问题,涉及到的知识点。
主要是以下四个类会考的比较多,他们共同的作用都是为了协助线程的同步
- 闭锁 CountDownLatch
- 栅栏 CyclicBarrier
- 信号量 Semaphore
- 交换器 Exchanger
- 闭锁 CountDownLatch
闭锁主要做的是让主线程等待一组事件发生后再继续执行,这里的事件其实指的就是CountDownLatch里面的countDown()方法。
图中也正是描述了这个意思,countDown()方法将会被一个个线程去执行,每当执行结束之后,越过CountDownLatch之后,子线程T1 T2 T3不会受到约束,将会继续执行,而主线程TA,需要所有子线程都已经执行完CountDown方法之后,才能继续执行。
那么我们要如何去判断所有线程都执行到了呢?
就是靠CountDownLatch()里面的一个cnt计数器,这个计数器的初始值就是线程的条数,每当一个线程执行过countDown()方法之后,就会减一,减到0的时候,主线程才会继续推进执行。
我们也可以写个Demo来看一下实际的效果:
- 栅栏 CyclicBarrier
它可以做到的的是阻塞当前线程,等待其他线程,其中
- 等待其他线程,且会阻塞自己的当前线程,所有线程必须同时到达栅栏,才能继续执行。
- 所有线程到达栅栏的时候,可以触发执行另外一个预先设置的触发器流程。
和CountDownLatch一样,CyclicBarrier内部也有一个计数器,T1 T2 T3线程每次调用一个await(),计数器就会减一,而当计数器为0的时候,主线程才会继续执行。
和CountDownLatch的区别在于:CountDownLatch的子线程,是不受到约束的,可以继续执行,只是执行过countdown方法之后,计数器减一而已,但是CyclicBarrier的子线程会被阻塞,等待其他子线程,等都执行完了之后才会继续执行。
- 信号量 Semaphore
Semaphore的作用是,可以控制一个资源最多被多少个线程同时访问,通过acquire去获取到一个许可,如果没有就等待,如果线程的任务完成了,就会执行release方法,去释放出一个许可出来,让其他线程再获取到acquire许可,使用资源。
也写一个Demo看一下:
运行之后是可以感受到一种阻塞的感觉的
- 交换器 Exchanger
在Exchanger中,有一个同步点,在同步点中,两个线程可以互相交换彼此的数据,当一个线程到达同步点之后,就会阻塞,等待之后另一个线程到达同步点之后,开始交换数据。Exchanger只能用于两个线程互相交换数据。
也是写一个程序看一下
当使用exchange这个api的时候,交换的同步点就已经触发了。
2. Collections
在之前,我们讲过了ConcurrentHashMap,现在来讲另一个也很重要的队列,BlockingQueue
- BlockingQueue:提供可阻塞的入队和出队操作
意思就是说,队列满了,入队操作将会阻塞,直到有空间可用,如果队列空了,出队操作将阻塞,直到有元素可用,根据我们以往学的数据结构,我们可以来看看它的底层代码,介绍几个常用的方法:
尝试往队尾添加元素,添加成功返回true,添加失败就抛出异常
offer作用和add一样,但是如果添加失败就返回false,并且offer还有一个重载的方法
意思是,如果添加失败,会等待unit秒,相当于给个机会
put和以上两者作用相同,但是如果添加失败,就会不断等待,直到可以添加。
介绍完放了,再介绍一下取:
这个方法和put对应,指的是从队列头取出元素,如果队列为空,就会一直等待,直到有元素为止。
这个poll和offer的重载方法对应,也是从队列头取出元素,相当于给个机会。
之后再讲讲其他的方法
获取当前队列剩余可存储元素的数量。
大致了解了BlockingQueue的方法之后,我们就再来说说BlockingQueue的使用场景
它主要用于生产者-消费者模型,在多线程场景中,生产者线程在队列尾部添加元素而消费者线程则在队列头部消费元素,通过这种方式能够达到将任务的生产和消费进行隔离的目的
BlockingQueue也是一个interface,它有以下几种实现的形式:
- ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列
- LinkedBlockingQueue:一个由链表结构组成的有界/无界阻塞队列
- PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列
- DealyQueue:一个使用优先级队列实现的无界阻塞队列
- SynchronousQueue:一个不存储元素的阻塞队列
- LinkedTransferQueue:一个由链表结构组成的无界阻塞队列
- LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列