JAVA阻塞队列LinkedBlockingQueue 以及非阻塞队列ConcurrentLinkedQueue 的区别

来源:互联网 发布:打印机排版软件 编辑:程序博客网 时间:2024/05/17 08:46

阻塞队列:线程安全

按 FIFO(先进先出)排序元素。队列的头部 是在队列中时间最长的元素。队列的尾部 是在队列中时间最短的元素。新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。

注意:

1、必须要使用take()方法在获取的时候达成阻塞结果
2、使用poll()方法将产生非阻塞效果

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.LinkedBlockingDeque;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.TimeUnit; public class BlockingDeque {    //阻塞队列,FIFO    private static LinkedBlockingQueue<Integer> concurrentLinkedQueue = new LinkedBlockingQueue<Integer>();            public static void main(String[] args) {       ExecutorService executorService = Executors.newFixedThreadPool(2);       executorService.submit(new Producer("producer1"));       executorService.submit(new Producer("producer2"));       executorService.submit(new Producer("producer3"));       executorService.submit(new Consumer("consumer1"));       executorService.submit(new Consumer("consumer2"));       executorService.submit(new Consumer("consumer3"));   }   static class Producer implements Runnable {       private String name;       public Producer(String name) {           this.name = name;       }       public void run() {           for (int i = 1; i < 10; ++i) {               System.out.println(name+ "  生产: " + i);               //concurrentLinkedQueue.add(i);               try {                concurrentLinkedQueue.put(i);                Thread.sleep(200); //模拟慢速的生产,产生阻塞的效果            } catch (InterruptedException e1) {                // TODO Auto-generated catch block                e1.printStackTrace();            }                      }       }   }   static class Consumer implements Runnable {       private String name;       public Consumer(String name) {           this.name = name;       }       public void run() {           for (int i = 1; i < 10; ++i) {               try {                              //必须要使用take()方法在获取的时候阻塞                      System.out.println(name+"消费: " +  concurrentLinkedQueue.take());                        //使用poll()方法 将产生非阻塞效果                      //System.out.println(name+"消费: " +  concurrentLinkedQueue.poll());                                            //还有一个超时的用法,队列空时,指定阻塞时间后返回,不会一直阻塞                     //但有一个疑问,既然可以不阻塞,为啥还叫阻塞队列?                    //System.out.println(name+" Consumer " +  concurrentLinkedQueue.poll(300, TimeUnit.MILLISECONDS));                                    } catch (Exception e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }           }       }   }  }

得到:

producer2  生产: 1
producer1  生产: 1
producer1  生产: 2
producer2  生产: 2
producer1  生产: 3
producer2  生产: 3
producer1  生产: 4
producer2  生产: 4
producer1  生产: 5
producer2  生产: 5
producer1  生产: 6
producer2  生产: 6
producer2  生产: 7
producer1  生产: 7
producer2  生产: 8
producer1  生产: 8
producer2  生产: 9
producer1  生产: 9
producer3  生产: 1
consumer1消费: 1
consumer1消费: 1
consumer1消费: 2
consumer1消费: 2
consumer1消费: 3
consumer1消费: 3
consumer1消费: 4
consumer1消费: 4
consumer1消费: 5
consumer2消费: 5
consumer2消费: 6
consumer2消费: 6
consumer2消费: 7
consumer2消费: 7
consumer2消费: 8
consumer2消费: 8
consumer2消费: 9
consumer2消费: 9
consumer3消费: 1
producer3  生产: 2
consumer3消费: 2
producer3  生产: 3
consumer3消费: 3
producer3  生产: 4
consumer3消费: 4
producer3  生产: 5
consumer3消费: 5
producer3  生产: 6
consumer3消费: 6
producer3  生产: 7
consumer3消费: 7
producer3  生产: 8
consumer3消费: 8
producer3  生产: 9
consumer3消费: 9

非阻塞队列

基于链接节点的、无界的、线程安全。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部,队列检索操作从队列头部获得元素。当许多线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许 null 元素。


import java.util.concurrent.ConcurrentLinkedQueue;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.LinkedBlockingDeque;import java.util.concurrent.TimeUnit;public class NoBlockQueue {         private static ConcurrentLinkedQueue<Integer> concurrentLinkedQueue = new ConcurrentLinkedQueue<Integer>();                 public static void main(String[] args) {          ExecutorService executorService = Executors.newFixedThreadPool(2);          executorService.submit(new Producer("producer1"));          executorService.submit(new Producer("producer2"));          executorService.submit(new Producer("producer3"));          executorService.submit(new Consumer("consumer1"));          executorService.submit(new Consumer("consumer2"));          executorService.submit(new Consumer("consumer3"));      }        static class Producer implements Runnable {          private String name;            public Producer(String name) {              this.name = name;          }            public void run() {              for (int i = 1; i < 10; ++i) {                  System.out.println(name+ " start producer " + i);                  concurrentLinkedQueue.add(i);                  try {                    Thread.sleep(20);                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }                //System.out.println(name+"end producer " + i);              }          }      }        static class Consumer implements Runnable {          private String name;            public Consumer(String name) {              this.name = name;          }          public void run() {              for (int i = 1; i < 10; ++i) {                  try {                     System.out.println(name+" Consumer " +  concurrentLinkedQueue.poll());                } catch (Exception e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }  //                System.out.println();  //                System.out.println(name+" end Consumer " + i);              }          }      }  }


得到:

producer1 start producer 1
producer2 start producer 1
producer1 start producer 2
producer2 start producer 2
producer1 start producer 3
producer2 start producer 3
producer1 start producer 4
producer2 start producer 4
producer1 start producer 5
producer2 start producer 5
producer1 start producer 6
producer2 start producer 6
producer1 start producer 7
producer2 start producer 7
producer1 start producer 8
producer2 start producer 8
producer1 start producer 9
producer2 start producer 9
producer3 start producer 1
consumer1 Consumer 1
consumer1 Consumer 1
consumer1 Consumer 2
consumer1 Consumer 2
consumer1 Consumer 3
consumer1 Consumer 3
consumer1 Consumer 4
consumer1 Consumer 4
consumer1 Consumer 5
consumer2 Consumer 5
consumer2 Consumer 6
consumer2 Consumer 6
consumer2 Consumer 7
consumer2 Consumer 7
consumer2 Consumer 8
consumer2 Consumer 8
consumer2 Consumer 9
consumer2 Consumer 9
consumer3 Consumer 1
consumer3 Consumer null
consumer3 Consumer null
consumer3 Consumer null
consumer3 Consumer null
consumer3 Consumer null
consumer3 Consumer null
consumer3 Consumer null
consumer3 Consumer null
producer3 start producer 2
producer3 start producer 3
producer3 start producer 4
producer3 start producer 5
producer3 start producer 6
producer3 start producer 7
producer3 start producer 8
producer3 start producer 9

在并发编程中,一般推荐使用阻塞队列,这样实现可以尽量地避免程序出现意外的错误。阻塞队列使用最经典的场景就是socket客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。还有其他类似的场景,只要符合生产者-消费者模型的都可以使用阻塞队列。

 

使用非阻塞队列,虽然能即时返回结果(消费结果),但必须自行编码解决返回为空的情况处理(以及消费重试等问题)。

另外他们都是线程安全的,不用考虑线程同步问题。









阅读全文
0 0
原创粉丝点击