队列 LinkedBlockingQueue
1 api
java.util.concurrent包下的新类。LinkedBlockingQueue就是其中之一,是一个阻塞的线程安全的队列,底层采用链表实现。
LinkedBlockingQueue构造的时候若没有指定大小,则默认大小为Integer.MAX_VALUE,当然也可以在构造函数的参数中指定大小。LinkedBlockingQueue不接受null。
添加元素的方法有三个:add,put,offer,且这三个元素都是向队列尾部添加元素的意思。
区别:
add方法在添加元素的时候,若超出了度列的长度会直接抛出异常:
xxxxxxxxxx
16
16
1
public static void main(String args[]){
2
try {
3
LinkedBlockingQueue<String> queue=new LinkedBlockingQueue(2);
4
5
queue.add("hello");
6
queue.add("world");
7
queue.add("yes");
8
} catch (Exception e) {
9
// TODO: handle exception
10
e.printStackTrace();
11
}
12
}
13
//运行结果:
14
java.lang.IllegalStateException: Queue full
15
at java.util.AbstractQueue.add(Unknown Source)
16
at com.wjy.test.GrandPather.main(GrandPather.java:12)
xxxxxxxxxx
17
17
1
public static void main(String args[]){
2
try {
3
LinkedBlockingQueue<String> queue=new LinkedBlockingQueue(2);
4
5
queue.put("hello");
6
queue.put("world");
7
queue.put("yes");
8
9
System.out.println("yes");
10
} catch (Exception e) {
11
// TODO: handle exception
12
e.printStackTrace();
13
}
14
}
15
//运行结果:
16
//在queue.put("yes")处发生阻塞
17
//下面的“yes”无法输出
offer方法在添加元素时,如果发现队列已满无法添加的话,会直接返回false。
xxxxxxxxxx
22
22
1
public static void main(String args[]){
2
try {
3
LinkedBlockingQueue<String> queue=new LinkedBlockingQueue(2);
4
5
boolean bol1=queue.offer("hello");
6
boolean bol2=queue.offer("world");
7
boolean bol3=queue.offer("yes");
8
9
System.out.println(queue.toString());
10
System.out.println(bol1);
11
System.out.println(bol2);
12
System.out.println(bol3);
13
} catch (Exception e) {
14
// TODO: handle exception
15
e.printStackTrace();
16
}
17
}
18
//运行结果:
19
[hello, world]
20
true
21
true
22
false
从队列中取出并移除头元素的方法有:poll,remove,take。
poll: 若队列为空,返回null。
remove:若队列为空,抛出NoSuchElementException异常。
take:若队列为空,发生阻塞,等待有元素。
2基于 LinkedBlockingQueue的生产者和消费者
85
1
package com.queue;
2
import java.util.concurrent.BlockingQueue;
3
import java.util.concurrent.ExecutorService;
4
import java.util.concurrent.Executors;
5
import java.util.concurrent.LinkedBlockingQueue;
6
public class LinkedBlockingQueueTest1 {
7
public static void main(String[] args) {
8
LinkedBlockingQueueTest1 test = new LinkedBlockingQueueTest1();
9
// 建立一个装苹果的篮子
10
Basket basket = test.new Basket();
11
ExecutorService service = Executors.newCachedThreadPool();
12
Producer producer = test.new Producer("生产者001", basket);
13
Producer producer2 = test.new Producer("生产者002", basket);
14
Consumer consumer = test.new Consumer("消费者001", basket);
15
service.submit(producer);
16
service.submit(producer2);
17
service.submit(consumer);
18
// 程序运行5s后,所有任务停止
19
try {
20
Thread.sleep(1000 * 5);
21
} catch (InterruptedException e) {
22
e.printStackTrace();
23
}
24
service.shutdownNow();
25
}
26
27
//定义篮子
28
public class Basket {
29
// 篮子,能够容纳3个苹果
30
BlockingQueue<String> basket = new LinkedBlockingQueue<String>(3);
31
// 生产苹果,放入篮子
32
public void produce() throws InterruptedException {
33
// put方法放入一个苹果,若basket满了,等到basket有位置
34
basket.put("An apple");
35
}
36
// 消费苹果,从篮子中取走
37
public String consume() throws InterruptedException {
38
// take方法取出一个苹果,若basket为空,等到basket有苹果为止(获取并移除此队列的头部)
39
return basket.take();
40
}
41
}
42
// 定义苹果生产者
43
class Producer implements Runnable {
44
private String instance;
45
private Basket basket;
46
public Producer(String instance, Basket basket) {
47
this.instance = instance;
48
this.basket = basket;
49
}
50
public void run() {
51
try {
52
while (true) {
53
// 生产苹果
54
System.out.println(instance + "生产苹果");
55
basket.produce();
56
// 休眠300ms
57
Thread.sleep(300);
58
}
59
} catch (InterruptedException ex) {
60
System.out.println("Producer Interrupted");
61
}
62
}
63
}
64
// 定义苹果消费者
65
class Consumer implements Runnable {
66
private String instance;
67
private Basket basket;
68
public Consumer(String instance, Basket basket) {
69
this.instance = instance;
70
this.basket = basket;
71
}
72
public void run() {
73
try {
74
while (true) {
75
// 消费苹果
76
System.out.println(instance + "消费苹果" + basket.consume());
77
// 休眠1000ms
78
Thread.sleep(150);
79
}
80
} catch (InterruptedException ex) {
81
System.out.println("Consumer Interrupted");
82
}
83
}
84
}
85
}
3示例2
并发库中的BlockingQueue是一个比较好玩的类,顾名思义,就是阻塞队列。该类主要提供了两个方法put()和take(),前者将一个对象放到队列中,如果队列已经满了,就等待直到有空闲节点;后者从head取一个对象,如果没有对象,就等待直到有可取的对象。
下面的例子比较简单,一个读线程,用于将要处理的文件对象添加到阻塞队列中,
另外四个写线程用于取出文件对象,为了模拟写操作耗时长的特点,特让线程睡眠一段随机长度的时间。另外,该Demo也使用到了线程池和原子整型(AtomicInteger),AtomicInteger可以在并发情况下达到原子化更新,避免使用了synchronized,而且性能非常高。由于阻塞队列的put和take操作会阻塞,为了使线程退出,特在队列中添加了一个“标识”,算法中也叫“哨兵”,当发现这个哨兵后,写线程就退出。
x
79
}
1
public class LinkedBlockingQueueTest {
2
static long randomTime() {
3
return (long) (Math.random() * 1000);
4
}
5
6
public void testName() throws Exception {
7
AtomicInteger rc = new AtomicInteger();
8
int incrementAndGet = rc.incrementAndGet();
9
System.out.println(incrementAndGet);
10
}
11
12
13
public static void main(String[] args) {
14
// 能容纳100个文件
15
final BlockingQueue<File> queue = new LinkedBlockingQueue<File>(100);
16
// 线程池
17
final ExecutorService exec = Executors.newFixedThreadPool(5);
18
final File root = new File("D:\\JavaLib");
19
// 完成标志
20
final File exitFile = new File("");
21
// 读个数
22
final AtomicInteger rc = new AtomicInteger();
23
// 写个数
24
final AtomicInteger wc = new AtomicInteger();
25
// 读线程
26
Runnable read = new Runnable() {
27
public void run() {
28
scanFile(root);
29
scanFile(exitFile);
30
}
31
public void scanFile(File file) {
32
if (file.isDirectory()) {
33
File[] files = file.listFiles(new FileFilter() {
34
public boolean accept(File pathname) {
35
return pathname.isDirectory() || pathname.getPath().endsWith(".java");
36
}
37
});
38
for (File one : files)
39
scanFile(one);
40
} else {
41
try {
42
int index = rc.incrementAndGet();
43
System.out.println("Read0: " + index + " " + file.getPath());
44
queue.put(file);
45
} catch (InterruptedException e) {
46
}
47
}
48
}
49
};
50
exec.submit(read);
51
// 四个写线程
52
for (int index = 0; index < 4; index++) {
53
// write thread
54
final int NO = index;
55
Runnable write = new Runnable() {
56
String threadName = "Write" + NO;
57
public void run() {
58
while (true) {
59
try {
60
Thread.sleep(randomTime());
61
int index = wc.incrementAndGet();
62
File file = queue.take();
63
// 队列已经无对象
64
if (file == exitFile) {
65
// 再次添加"标志",以让其他线程正常退出
66
queue.put(exitFile);
67
break;
68
}
69
System.out.println(threadName + ": " + index + " " + file.getPath());
70
} catch (InterruptedException e) {
71
}
72
}
73
}
74
};
75
exec.submit(write);
76
}
77
exec.shutdown();
78
}
79
}
满载一船星辉,在星辉斑斓里放歌
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步