七叶笔记 » java编程 » 深入理解Java并发编程之LinkedBlockingQueue队列

深入理解Java并发编程之LinkedBlockingQueue队列

当调用线程在LinkedBlockingQueue 实例上执行take、poll 等操作时需要获取到 takeLock 锁,从而保证同时只有一个线程可以操作链表头节点。另外由于条件变量 notEmpty 内部的条件队列的维护使用的是takeLock的锁状态管理机制,所以在调用notEmpty的await 和signal方法前调用线程必须先获取到 takeLock锁,否则会抛出IllegalMonitorStateException 异常。notEmpty内部则维护着一个条件队列,当线程获取到takeLock 锁后调用 notEmpty的await 方法时,调用线程会被阻塞,然后该线程会被放到notEmpty内部的条件队列进行等待,直到有线程调用了notEmpty的 signal 方法。

在LinkedBlockingQueue实例上执行put、offer等操作时需要获取到putLock锁,从而保证同时只有一个线程可以操作链表尾节点。同样由于条件变量 notFull 内部的条件队列的维护使用的是putLock的锁状态管理机制,所以在调用 notFull 的 await 和 signal 方法前调用线程必须先获取到putLock锁,否则会抛出 IllegalMonitorStateException 异常。notFull 内部则维护着一个条件队列,当线程获取到 putLock 锁后调用notFull的await 方法时,调用线程会被阻塞,然后该线程会被放到notFull 内部的条件队列进行等待,直到有线程调用了 notFull 的 signal 方法。如下是LinkedBlockingQueue 的无参构造函数的代码。

如下是LinkedBlockingQueue的无参构造代码

由该代码可知,默认队列容量为0x7fffffff,用户也可以自己指定容量,所以从一定程度上可以说LinkedBlockingQueue是有界阻塞队列。

offer操作

代码(2)判断如果当前队列已满则丢弃当前元素并返回false

代码(3)获取到 putLock 锁,当前线程获取到该锁后,则其他调用put和 offer操的线程将会被阻塞(阻塞的线程被放到putLock锁的AQS阻塞队列)。

代码(4)这里重新判断当前队列是否满,这是因为在执行代码(2)和获取到 putLock 锁期间可能其他线程通过 put 或者offer 操作向队列里面添加了新元素。重新判斯队列确实不满则新元素入队,并递增计数器。

代码(5)判断如果新元素入队后队列还有空闲空间,则唤醒notFull的条件队列里面因为调用了notFull的await操作(比如执行put方法而队列满了的时候)而被阻塞的一个线程,因为队列现在有空闲所以这里可以提前唤醒一个入队线程。

代码(6)则释放获取的putLock 锁,这里要注意,锁的释放一定要在finally里面做因为即使try块抛出异常了,finally也是会被执行到。另外释放锁后其他因为调用put 操作而被阻塞的线程将会有一个获取到该锁。

代码(7)中的c0说明在执行代码(6)释放锁时队列里面至少有一个元素,队列里面有元素则执行signalNotEmpty操作.

到此这篇关于深入理解Java并发编程之LinkedBlockingQueue队列的文章就介绍到这了,更多相关Java LinkedBlockingQueue队列内容请搜索七叶笔记以前的文章或继续浏览下面的相关文章希望大家以后多多支持七叶笔记!

相关文章