获取许可证
acquire()方法最终调用父类AQS中的acquireSharedInterruptibly方法。
(1):调用tryAcquireShared,尝试去获取许可证
(2):如果获取失败,则调用doAcquireSharedInterruptibly,将线程加入到等待队列中
tryAcquireShared方法由Semaphore的内部类,同时也是AQS的子类去实现,即NonfairSync和FairSync,下面我们以NonfairSync为例说明其实现。
而nonfairTryAcquireShared方法如下:
final int nonfairTryAcquireShared(int acquires) { for (;;) { int available = getState(); //(1) int remaining = available - acquires; //(2) if (remaining < 0 || compareAndSetState(available, remaining)) (3) return remaining; } }(1):获取state的值,也就是总许可证数量
(2):计算本次申请后,剩余的许可证数量
(3):如果剩余的许可证数量大于0且通过CAS将state的值修改成功后,返回剩余的许可证数量,否则继续循环阻塞。
释放许可证
release()方法的调用最终会调用父类AQS的releaseShared()方法:
(1):尝试释放许可证
(2):如果释放许可证成功,则通知阻塞的线程,让其执行
tryReleaseShared方法很简单,基本上是nonfairTryAcquireShared的逆过程,即增加许可证的数量,并通过CAS修改state的值。
阻塞队列主要是解决如何高效安全传输数据的问题,此外能降低程序耦合度,让代码逻辑更加清晰。
其继承了Queue,并在其基础上支持了两个附加的操作:
当队列为空时,获取元素的线程会阻塞,等待队列变为非空
当队列满时,添加元素的线程会阻塞,等待队列可用
比较典型的使用场景是生产者和消费者。
BlockingQueue根据对于不能立即满足但可能在将来某一时刻可以满足的操作,提供了不同的处理方法,进而导致众多的api操作:
Throws exception
Special value
Blocks
Times out
Insert
add(e)
offer(e)
put(e)
offer(e, time, unit)
Remove
remove()
poll()
take()
poll(time, unit)
Examine
element()
peek()}
not applicable
not applicable
Throws exception:指当阻塞队列满时候,再往队列里插入元素,会抛出IllegalStateException异常。当队列为空时,从队列里获取元素时会抛出NoSuchElementException异常
Special value:插入方法会返回是否成功,成功则返回true。移除方法,则是从队列里拿出一个元素,如果没有则返回null
Blocks:当阻塞队列满时,如果生产者线程往队列里put元素,队列会一直阻塞生产者线程,直到拿到数据,或者响应中断退出。当队列空时,消费者线程试图从队列里take元素,队列也会阻塞消费者线程,直到队列可用。
Time out:当阻塞队列满时,队列会阻塞生产者线程一段时间,如果超过一定的时间,生产者线程就会退出。
Java并发包根据不同的结构和功能提供了不同的阻塞队列,整体类图如下:
其中BlockingQueue有如下子类:
ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
其中BlockingDeque有一个子类: