Java并发编程工具类JUC中,LinkedBlockingQueue是一种基于链表的阻塞队列。它可以支持多线程并发访问,是用于多线程交换数据的缓冲区。下面详细讲解一下该队列的使用方法。
LinkedBlockingQueue的特点和操作方法
特点
LinkedBlockingQueue内部采用了一种“等待-通知”机制,当试图向队列中添加元素时,如果队列已满,就会阻塞等待;当试图从队列中取出元素时,如果队列为空,就会阻塞等待。
操作方法
LinkedBlockingQueue的操作方法与其他队列相似,主要有以下方法:
put(E e)
: 添加一个元素,如果队列满,则阻塞等待take()
: 取出并删除队列的头元素,如果队列为空,则阻塞等待offer(E e)
: 添加一个元素,如果队列已满,则返回false,否则返回truepoll()
: 取出并删除队列的头元素,如果队列为空,则返回nullsize()
: 返回队列元素个数
LinkedBlockingQueue示例
示例一:线程池任务队列
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
// 创建一个线程池,最多可以同时执行2个线程
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 2, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(5)
);
// 向线程池提交10个任务
for (int i = 0; i < 10; i++) {
executor.execute(new MyTask(String.valueOf(i)));
}
// 关闭线程池
executor.shutdown();
}
}
class MyTask implements Runnable {
private String name;
public MyTask(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " start: " + name);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " end: " + name);
}
}
在这个示例中,我们创建了一个线程池,使用了LinkedBlockingQueue来作为任务队列,设置了队列的容量为5。向线程池中提交了10个任务,线程池最多可以同时执行2个线程,当任务队列中元素数量达到5时,将不再接受新的任务,直到有线程执行完任务后才会把队列中的元素移除,这样就避免了任务过多导致内存溢出的情况。其中,MyTask实现了Runnable接口,任务执行完毕后打印出线程名称和任务名称。
示例二:多生产者多消费者模型
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class Main {
public static void main(String[] args) {
// 创建一个队列,最多可以存放5个元素
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5);
// 启动3个生产者线程
for (int i = 1; i <= 3; i++) {
new Producer(queue, i).start();
}
// 启动2个消费者线程
for (int i = 1; i <= 2; i++) {
new Consumer(queue, i).start();
}
}
}
class Producer extends Thread {
private final BlockingQueue<Integer> queue;
private final int num;
public Producer(BlockingQueue<Integer> queue, int num) {
this.queue = queue;
this.num = num;
}
@Override
public void run() {
try {
while (true) {
int i = (int) (Math.random() * 100);
queue.put(i);
System.out.println("Producer " + num + " puts: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Consumer extends Thread {
private final BlockingQueue<Integer> queue;
private final int num;
public Consumer(BlockingQueue<Integer> queue, int num) {
this.queue = queue;
this.num = num;
}
@Override
public void run() {
try {
while (true) {
int i = queue.take();
System.out.println("Consumer " + num + " takes: " + i);
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在这个示例中,我们创建了一个容量为5的阻塞队列,启动了3个生产者线程和2个消费者线程,生产者线程不断生成随机数并将其放入队列中,消费者线程不断从队列中取出元素并打印出来。由于队列的容量限制,当队列中元素已满时,生产者线程将会被阻塞,直到队列中有元素被消费掉,才有可能继续向队列中添加元素;当队列为空时,消费者线程将会被阻塞,直到队列中有元素被添加到队列中,才有可能从队列中取出元素。通过这种方式,多个生产者线程和多个消费者线程可以高效地并发访问队列。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java并发编程工具类JUC之LinkedBlockingQueue链表队列 - Python技术站