Java阻塞队列poll_Java 并发 - 阻塞队列

本文详细介绍了Java阻塞队列的概念、作用及其在生产者-消费者问题中的应用。重点讲解了ArrayBlockingQueue、LinkedBlockingQueue和SynchronousQueue三种实现,并展示了基于阻塞队列的生产者消费者模型实现,强调了阻塞队列如何避免资源不足或资源满导致的问题,以及在线程池和消息队列中的应用。
摘要由CSDN通过智能技术生成

一、概念

具有以下性质的队列:

阻塞队列空,从队列取元素操作会被阻塞,直到有新元素加入

阻塞队列满,从队列加元素操作会被阻塞,直到有旧元素加入

二、作用

阻塞队列的作用也就是其好处:自动管理了阻塞 / 唤醒线程的时机

在这东西出来前,程序员需要自动管理,通过 wait / notify 这样的机制,写起来麻烦

三、BlockingQueue

3.1 体系

继承 Collection 接口,具有七个实现类,常用的三个:

ArrayBlockingQueue:数组构成的有界阻塞队列

LinkedBlockingQueue:链表构成的有界(Integer.MAX_VALUE)阻塞队列

SynchronousQueue:只存单个元素的阻塞队列

3.2 API

插入、删除对应四种形式的 API:

抛出异常

特殊值

阻塞

超时

检查对应两种形式的 API:

抛出异常

特殊值

抛出异常

特殊值

阻塞

超时

插入

add(e)

offer(e)

put(e)

offer(e, time, unit)

移除

remove(e)

poll()

take()

poll(time, unit)

检查

element()

peek()

抛出异常

插入、移除、检查失败则抛出异常

特殊值

插入,返回成功 true,失败 false

移除,成功返回队列移除元素

阻塞

插入、移除检查失败则阻塞

四、应用

4.1 生产者 - 消费者

4.1.1 实现方式

基于 synchronized / wait / notifyAll :重量锁与 Object 自带方法

基于 ReentrantLock / await / signalAll:可重入锁与 Condition 方法

基于 ArrayBlockingQueue / put / take:阻塞队列及自带方法

4.2 ReentrantLock / Condition

多生产者与多消费者 Condition 版本:

class Product {

private int num;

private int capacity = 1;

private Lock lock = new ReentrantLock();

private Condition condition = lock.newCondition();

public void increment() throws InterruptedException {

lock.lock();

try {

while (num == capacity) {

condition.await();

}

num++;

System.out.println(Thread.currentThread().getName() +

" create, and product remain:\t" +

num);

condition.signalAll();

} finally {

lock.unlock();

}

}

public void decrement() throws InterruptedException {

lock.lock();

try {

while (num == 0) {

condition.await();

}

num--;

System.out.println(Thread.currentThread().getName() +

" cost, and product remain:\t" +

num);

condition.signalAll();

} finally {

lock.unlock();

}

}

}

class Test {

public static void main(String[] args) {

Product product = new Product();

for (int i = 1; i <= 5; i++) {

new Thread(() -> {

try {

product.increment();

} catch (InterruptedException e) {

e.printStackTrace();

}

}, "T" + i).start();

}

for (int i = 6; i <= 10; i++) {

new Thread(() -> {

try {

product.decrement();

} catch (InterruptedException e) {

e.printStackTrace();

}

}, "T" + i).start();

}

}

}

生产者消费者阻塞队列版:

class Producer extends Thread {

private BlockingQueue blockingQueue;

public Producer(BlockingQueue blockingQueue) {

this.blockingQueue = blockingQueue;

}

@Override

public void run() {

try {

this.blockingQueue.put("product");

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

System.out.println(Thread.currentThread().getName() + " is producing...");

}

}

}

class Consumer extends Thread {

private BlockingQueue blockingQueue;

public Consumer(BlockingQueue blockingQueue) {

this.blockingQueue = blockingQueue;

}

@Override

public void run() {

try {

this.blockingQueue.take();

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

System.out.println(Thread.currentThread().getName() + " is consuming...");

}

}

}

class Test {

public static void main(String[] args) throws InterruptedException {

BlockingQueue blockingQueue = new ArrayBlockingQueue<>(1);

for (int i = 1; i <= 3; i++) {

new Producer(blockingQueue).start();

}

for (int i = 1; i <= 3; i++) {

new Consumer(blockingQueue).start();

}

}

}

注意:线程取值和读值具有无序性,所以可能发生消费在生产之前,但底层绝不会存在资源不够,但还能被消费者消费的现象,若资源不够 / 资源满,就会阻塞,这是肯定的

4.3 线程池

内部的任务队列,其实就是使用了 LinkedBlockingQueue 等阻塞队列实现的

4.4 消息队列

消息队列是基于 生产者-消费者 为核心的架构设计的,而一般可以使用阻塞队列来实现这一模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值