Java多线程案例之阻塞队列详解
什么是阻塞队列?
阻塞队列(Blocking Queue)是一个支持在队列的两端进行插入与删除的队列。常用的阻塞队列有ArrayBlockingQueue、LinkedBlockingQueue等。阻塞队列在多线程的场景下常被使用,因为当队列为空或达到容量上限时,线程往往会被阻塞。在队列空的情况下,从队列中获取元素的操作将会被阻塞,直到有元素加入到队列中;在队列满的情况下,插入元素的操作将会被阻塞,直到队列中有元素被移除。
Java中的阻塞队列
ArrayBlockingQueue
ArrayBlockingQueue 是一个基于数组结构实现的有界阻塞队列,其内部实现使用了ReentrantLock(可重入锁)来保证操作的线程安全性。
可以使用以下代码创建一个ArrayBlockingQueue:
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
LinkedBlockingQueue
LinkedBlockingQueue 是一个基于链表结构实现的有界(大小默认是Integer.MAX_VALUE)阻塞队列,其内部实现使用了两个ReentrantLock和两个Condition来保证对队列的插入和删除操作的线程安全性。
可以使用以下代码创建一个LinkedBlockingQueue:
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
示例说明
ArrayBlockingQueue 示例
以下示例展示了一个使用ArrayBlockingQueue实现的生产者消费者模型。
public class ProducerConsumerDemo {
private static BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
public static void main(String[] args) {
Thread producerThread = new Thread(new Producer());
Thread consumerThread = new Thread(new Consumer());
producerThread.start();
consumerThread.start();
}
static class Producer implements Runnable {
@Override
public void run() {
while (true) {
try {
queue.put(new Random().nextInt(100));
System.out.println("生产者生产了一个商品,当前队列大小:" + queue.size());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class Consumer implements Runnable {
@Override
public void run() {
while (true) {
try {
queue.take();
System.out.println("消费者消费了一个商品,当前队列大小:" +queue.size());
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
在这个示例中,生产者线程负责往阻塞队列中添加数据(即商品),如果队列已满,则会被阻塞。消费者线程负责从阻塞队列中取出数据(即消费商品),如果队列为空,则会被阻塞。
LinkedBlockingQueue 示例
以下示例展示了一个使用LinkedBlockingQueue实现的线程池模型。
public class ThreadPoolDemo {
private static ExecutorService executorService = new ThreadPoolExecutor(3, 6, 500, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10));
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
executorService.execute(new Worker(i));
}
executorService.shutdown();
}
static class Worker implements Runnable {
private int id;
public Worker(int id) {
this.id = id;
}
@Override
public void run() {
try {
System.out.println("当前执行线程:" + id + ",剩余线程:" + ((ThreadPoolExecutor) executorService).getQueue().remainingCapacity()));
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
在这个示例中,通过ThreadPoolExecutor来创建一个线程池,并使用LinkedBlockingQueue来作为任务队列。当线程池的线程数达到核心线程数(3)时,多余的任务会被放入LinkedBlockingQueue中等待执行。如果队列已满,则会阻塞新的任务。在这个示例中,最多执行9个Worker对象的run方法。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程案例之阻塞队列详解 - Python技术站