队列 LinkedBlockingQueue
1 api
java.util.concurrent包下的新类。LinkedBlockingQueue就是其中之一,是一个阻塞的线程安全的队列,底层采用链表实现。
LinkedBlockingQueue构造的时候若没有指定大小,则默认大小为Integer.MAX_VALUE,当然也可以在构造函数的参数中指定大小。LinkedBlockingQueue不接受null。
添加元素的方法有三个:add,put,offer,且这三个元素都是向队列尾部添加元素的意思。
区别:
add方法在添加元素的时候,若超出了度列的长度会直接抛出异常:
xxxxxxxxxx16
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) xxxxxxxxxx17
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。
xxxxxxxxxx22
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
// 休眠300ms57
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
// 休眠1000ms78
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 thread54
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
}
满载一船星辉,在星辉斑斓里放歌

浙公网安备 33010602011771号