⽤阻塞队列LinkedBlockingQueue实现⽣产者消费者先进先出
LinkedBlockingQueue是⼀个基于已链接节点的、范围任意的blocking queue的实现。 由于LinkedBlockingQueue实现是线程安全的,实现了先进先出等特性,是作为⽣产者消费者的⾸选,LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最⼤是Integer.MAX_VALUE,其中主要⽤到put和take⽅法,put⽅法在队列满的时候会阻塞直到有队列成员被消费,take⽅法在队列空的时候会阻塞,直到有队列成员被放进来。
汽车膜品牌此队列按 FIFO(先进先出)排序元素。队列的头部 是在队列中时间最长的元素。队列的尾部 是在队列中时间最短的元素。
新元素插⼊到队列的尾部,并且队列检索操作会获得位于队列头部的元素。链接队列的吞吐量通常要⾼于基于数组的队列,
悬挂系统
但是在⼤多数并发应⽤程序中,其可预知的性能要低。
可选的容量范围构造⽅法参数作为防⽌队列过度扩展的⼀种⽅法。
如果未指定容量,则它等于 Integer.MAX_VALUE。除⾮插⼊节点会使队列超出容量,否则每次插⼊后会动态地创建链接节点。
1:如果未指定容量,默认容量为Integer.MAX_VALUE ,容量范围可以在构造⽅法参数中指定作为防⽌队列过度扩展。
2:此对象是 线程阻塞-安全的
3:不接受 null 元素
4:它实现了BlockingQueue接⼝。
5:实现了 Collection 和 Iterator 接⼝的所有可选 ⽅法。
6:在JDK5/6中,LinkedBlockingQueue和ArrayBlocingQueue等对象的poll(long timeout, TimeUnit unit)存在内存泄露Leak的对象AbstractQueuedSynchronizer.Node,据称JDK5会在Update12⾥Fix,JDK6会在Update2⾥Fix
绿萝怎么浇水
⽰例代码如下:
[html]
1. package com.st;
2.
3. import urrent.BlockingQueue;
4. import urrent.LinkedBlockingQueue;
5.
6. public class TestBlockingQueue {
7. static BlockingQueue <Hamburger> queue=new LinkedBlockingQueue<Hamburger>(10);
8. public static void main(String[] args) throws InterruptedException {
9. Producer t1 = new Producer();
10. Consumer t2 = new Consumer();
11. t1.start();
蛋糕照片
12. t2.start();
13. System.out.println("Thread.sleep(1000)");
14. Thread.sleep(1000);
15. t2.interrupt();
16. }
17. }
18. class Hamburger{
19. int id;
20. public Hamburger(int id) {
21. this.id=id;
22. }
23.
24. public String toString() {
25. return "Hamburger: "+id;
26. }
27. }
28. class Producer extends Thread{
29.
30. public void run() {
31. int i=0;
32. while(i<10){
33. Hamburger e = new Hamburger(i);
34. try {
35. System.out.println("Produce Hamburger: "+i);
36. TestBlockingQueue.queue.put(e);
37. } catch (InterruptedException e1) {
38. System.out.println("Hamburger so many, it was clod.");
39. return;
40. }
41. i++;
42. }
43. }
44. }
45. class Consumer extends Thread{
46.
47. public void run() {
48. while(true){
49. try {
50. System.out.println("Eat Hamburger: "+TestBlockingQueue.queue.take());
51. } catch (InterruptedException e1) {
52. System.out.println("Hamburger so less, It was stopped.");
53. return;
属牛的幸运数字54. }
55. }
56. }
57. }
由于阻塞队列LinkedBlockingQueue,FIFO,使⽤它的put(),take()会判断当前队列是有值,即等待⽣产再消费,即便是两个线程并⾏执⾏,很简单⽅便的解决了⽣产者消费者问题,但是在这⾥需要注意的是在两个run()⽅法中,打印当前⽣产或消费Hamburger的时候,最好把put()和take()⽅法放在相应的打印语句中⼀起执⾏,否则会发⽣先消费后⽣产的后果。 因为打印语句和⽅法的执⾏时两段代码,由于双线程同时执⾏,⽆法保证执⾏的相应代码块的顺序性!!由于最后互相等待会造成死锁,所以在主线程睡眠1秒后打断消费者,让它别等了,抛异常后return结束消费线程,最后整个main⽅法调⽤结束。
ConcurrentLinkedQueue
ConcurrentLinkedQueue是Queue的⼀个安全实现.Queue中元素按FIFO原则进⾏排序.采⽤CAS操作,来保证元素的⼀致性。LinkedBlockingQueue是⼀个线程安全的阻塞队列,它实现了BlockingQueue接⼝,BlockingQueue接⼝继承⾃.util.Queue接⼝,并在这个接⼝的基础上增加了take和put⽅法,这两个⽅法正是队列操作的阻塞版本。
[html]
1. package com.st;
2.
风水住宅3. import urrent.ConcurrentLinkedQueue;
4. import urrent.CountDownLatch;
5. import urrent.ExecutorService;
6. import urrent.Executors;
7.
8. public class ConcurrentLinkedQueueTest {
9. private static ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<Integer>();
10. private static int count = 2; // 线程个数
11. //CountDownLatch,⼀个同步辅助类,在完成⼀组正在其他线程中执⾏的操作之前,它允许⼀个或多个线程⼀直等待。
12. private static CountDownLatch latch = new CountDownLatch(count);
13.
14. public static void main(String[] args) throws InterruptedException {
15. long timeStart = System.currentTimeMillis();
16. ExecutorService es = wFixedThreadPool(4);
17. ConcurrentLinkedQueueTest.offer();
18. for (int i = 0; i < count; i++) {
19. es.submit(new Poll());
20. }
21. latch.await(); //使得主线程(main)阻塞直到untDown()为零才继续执⾏
22. System.out.println("cost time " + (System.currentTimeMillis() - timeStart) + "ms");
23. es.shutdown();
24. }
25.
26. /**
27. * ⽣产
28. */
29. public static void offer() {
30. for (int i = 0; i < 100000; i++) {
31. queue.offer(i);
32. }
33. }
34.
35. /**
36. * 消费照相记忆
37. */
38. static class Poll implements Runnable {
39. public void run() {
40. while (queue.size()>0) {
41. // while (!queue.isEmpty()) {
42. System.out.println(queue.poll());
43. }
44. untDown();
45. }
46. }
47. }
运⾏结果:
costtime 1415ms
改⽤while (queue.size()>0)后
承诺函运⾏结果:
cost time 38214ms
结果居然相差那么⼤,看了下ConcurrentLinkedQueue的API原来.size()是要遍历⼀遍集合的,难怪那么慢,所以尽量要避免⽤size⽽改⽤isEmpty().
总结了下, 在缺乏性能测试下,对⾃⼰的编程要求更加要严格,特别是在⽣产环境下更是要⼩⼼谨慎。