java中的阻塞队列
2017-05-09 23:41
204 查看
一、阻塞队列(BlockingQueue) 是一个支持两个附加操作的队列。 这两个附加的操作支持阻塞的插入和移除方法。
1、支持阻塞的插入方法: 意思是当队列满时, 队列会阻塞插入元素的线程, 直到队列不满。
2、支持阻塞的移除方法: 意思是在队列为空时, 获取元素的线程会等待队列变为非空。
阻塞队列常用于生产者和消费者的场景, 生产者是向队列里添加元素的线程, 消费者是从队列里取元素的线程。 阻塞队列就是生产者用来存放元素、 消费者用来获取元素的容器。
在阻塞队列不可用时, 这两个附加操作提供了4种处理方式
1、抛出异常: 当队列满时, 如果再往队列里插入元素, 会抛出IllegalStateException("Queue full") 异常。 当队列空时, 从队列里获取元素会抛出NoSuchElementException异常。
2、返回特殊值: 当往队列插入元素时, 会返回元素是否插入成功, 成功返回true。 如果是移除方法, 则是从队列里取出一个元素, 如果没有则返回null。
3、一直阻塞: 当阻塞队列满时, 如果生产者线程往队列里put元素, 队列会一直阻塞生产者线程, 直到队列可用或者响应中断退出。 当队列空时, 如果消费者线程从队列里take元素, 队列会阻塞住消费者线程, 直到队列不为空。
4、超时退出: 当阻塞队列满时, 如果生产者线程往队列里插入元素, 队列会阻塞生产者线程一段时间, 如果超过了指定的时间, 生产者线程就会退出。
(注、如果是无界阻塞队列, 队列不可能会出现满的情况, 所以使用put或offer方法永远不会被阻塞, 而且使用offer方法时, 该方法永远返回true)
二、阻塞队列的实现原理。
使用通知模式实现。 所谓通知模式, 就是当生产者往满的队列里添加元素时会阻塞住生产者, 当消费者消费了一个队列中的元素后, 会通知生产者当前队列可用。
通过查看JDK源码发现ArrayBlockingQueue使用了Condition来实现, 代码如下所示:
private final Condition notFull;
private final Condition notEmpty;
public ArrayBlockingQueue(int capacity, boolean fair) {
// 省略其他代码
notEmpty = lock. newCondition() ;
notFull = lock. newCondition() ;
}
public void put(E e) throws InterruptedException {
checkNotNull(e) ;
final ReentrantLock lock = this. lock;
lock. lockInterruptibly() ;
try {
while (count == items. length)
notFull. await() ;
insert(e) ;
} finally {
lock. unlock() ;
}
}p
ublic E take() throws InterruptedException {
final ReentrantLock lock = this. lock;
lock. lockInterruptibly() ;
try {
while (count == 0)
notEmpty. await() ;
return extract() ;
} finally {
lock. unlock() ;
}
}p
rivate void insert(E x) {
items[ putIndex] = x;
putIndex = inc(putIndex) ;
++count;
notEmpty. signal() ;
}
1、支持阻塞的插入方法: 意思是当队列满时, 队列会阻塞插入元素的线程, 直到队列不满。
2、支持阻塞的移除方法: 意思是在队列为空时, 获取元素的线程会等待队列变为非空。
阻塞队列常用于生产者和消费者的场景, 生产者是向队列里添加元素的线程, 消费者是从队列里取元素的线程。 阻塞队列就是生产者用来存放元素、 消费者用来获取元素的容器。
在阻塞队列不可用时, 这两个附加操作提供了4种处理方式
1、抛出异常: 当队列满时, 如果再往队列里插入元素, 会抛出IllegalStateException("Queue full") 异常。 当队列空时, 从队列里获取元素会抛出NoSuchElementException异常。
2、返回特殊值: 当往队列插入元素时, 会返回元素是否插入成功, 成功返回true。 如果是移除方法, 则是从队列里取出一个元素, 如果没有则返回null。
3、一直阻塞: 当阻塞队列满时, 如果生产者线程往队列里put元素, 队列会一直阻塞生产者线程, 直到队列可用或者响应中断退出。 当队列空时, 如果消费者线程从队列里take元素, 队列会阻塞住消费者线程, 直到队列不为空。
4、超时退出: 当阻塞队列满时, 如果生产者线程往队列里插入元素, 队列会阻塞生产者线程一段时间, 如果超过了指定的时间, 生产者线程就会退出。
(注、如果是无界阻塞队列, 队列不可能会出现满的情况, 所以使用put或offer方法永远不会被阻塞, 而且使用offer方法时, 该方法永远返回true)
二、阻塞队列的实现原理。
使用通知模式实现。 所谓通知模式, 就是当生产者往满的队列里添加元素时会阻塞住生产者, 当消费者消费了一个队列中的元素后, 会通知生产者当前队列可用。
通过查看JDK源码发现ArrayBlockingQueue使用了Condition来实现, 代码如下所示:
private final Condition notFull;
private final Condition notEmpty;
public ArrayBlockingQueue(int capacity, boolean fair) {
// 省略其他代码
notEmpty = lock. newCondition() ;
notFull = lock. newCondition() ;
}
public void put(E e) throws InterruptedException {
checkNotNull(e) ;
final ReentrantLock lock = this. lock;
lock. lockInterruptibly() ;
try {
while (count == items. length)
notFull. await() ;
insert(e) ;
} finally {
lock. unlock() ;
}
}p
ublic E take() throws InterruptedException {
final ReentrantLock lock = this. lock;
lock. lockInterruptibly() ;
try {
while (count == 0)
notEmpty. await() ;
return extract() ;
} finally {
lock. unlock() ;
}
}p
rivate void insert(E x) {
items[ putIndex] = x;
putIndex = inc(putIndex) ;
++count;
notEmpty. signal() ;
}
相关文章推荐
- Java多线程 阻塞队列和并发集合
- java 之 阻塞队列实现
- 线程高级应用-心得7-java5线程并发库中阻塞队列Condition的应用及案例分析
- JAVA 阻塞队列 ArrayBlockingQueue
- Java5 多线程(八)-- ArrayBlockingQueue阻塞队列
- Java线程:新特征-阻塞队列
- Java多线程与并发库高级应用之阻塞队列BlockingQueue
- java 阻塞队列
- Java线程(十三):BlockingQueue-线程的阻塞队列
- Java多线程——4 阻塞队列
- 学习java多线程的笔记3-使用BlockingQueue阻塞队列来模拟两个线程之间的通信
- (13)多线程与并发库之java5阻塞队列(BlockingQueue)的应用----子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着再回到主线程循环100次,如此循环50次
- (10)java5条件阻塞Condition的应用<包含阻塞队列知识>
- JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue
- Java线程:新特征-阻塞队列
- Java多线程阻塞队列和并发集合
- (13)多线程与并发库之java5阻塞队列(BlockingQueue)的应用----子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着再回到主线程循环100次,如此循环50次
- 基于Java阻塞队列的搜索实例
- 基于Java阻塞队列实例(文件及文件内容搜索)
- Java多线程 阻塞队列和并发集合