(原創)JAVA阻塞隊列LinkedBlockingQueue 以及非阻塞隊列ConcurrentLinkedQueue 的區別

來源:互聯網
上載者:User
阻塞隊列:安全執行緒

按 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();                }           }       }   }  }
 

 

 

 

非阻塞隊列

基於連結節點的、無界的、安全執行緒。此隊列按照 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);              }          }      }  } 

 

在並發編程中,一般推薦使用阻塞隊列,這樣實現可以盡量地避免程式出現意外的錯誤。阻塞隊列使用最經典的情境就是socket用戶端資料的讀取和解析,讀取資料的線程不斷將資料放入隊列,然後解析線程不斷從隊列取資料解析。還有其他類似的情境,只要符合生產者-消費者模型的都可以使用阻塞隊列。

 

使用非阻塞隊列,雖然能即時返回結果(消費結果),但必須自行編碼解決返回為空白的情況處理(以及消費重試等問題)。

另外他們都是安全執行緒的,不用考慮線程同步問題。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.