国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java并發編程之阻塞隊列詳解

2019-11-26 14:29:21
字體:
來源:轉載
供稿:網友

1、什么是阻塞隊列?
  隊列是一種數據結構,它有兩個基本操作:在隊列尾部加入一個元素,從隊列頭部移除一個元素。阻塞隊里與普通的隊列的區別在于,普通隊列不會對當前線程產生阻塞,在面對類似消費者-生產者模型時,就必須額外的實現同步策略以及線程間喚醒策略。使用阻塞隊列,就會對當前線程產生阻塞,當隊列是空時,從隊列中獲取元素的操作將會被阻塞,當隊列是滿時,往隊列里添加元素的操作也會被阻塞。


2、主要的阻塞隊列及其方法

java.util.concurrent包下提供主要的幾種阻塞隊列,主要有以下幾個:

1)ArrayBlockingQueue:基于數組實現的阻塞隊列,在創建ArrayBlockingQueue對象時必須指定其容量大小,還可以指定訪問策略,默認情況下為非公平的,即不保證等待時間最長的線程最優先能夠訪問隊列。
2)、LinkedBlockingQueue:基于鏈表實現的一個阻塞隊列,在創建LinkedBlockingQueue對象時如果不指定容量大小,則默認大小為Integer.MAX_VALUE。
3)、以上2種隊列都是先進先出隊列,而PriorityBlockingQueue卻不是,它會按照元素的優先級對元素進行排序,按照優先級順序出隊,每次出隊的元素都是優先級最高的元素。注意,此阻塞隊列為無界阻塞隊列,即容量沒有上限(通過源碼就可以知道,它沒有容器滿的信號標志),前面2種都是有界隊列。
4)、DelayQueue:基于PriorityQueue,一種延時阻塞隊列,DelayQueue中的元素只有當其指定的延遲時間到了,才能夠從隊列中獲取到該元素。DelayQueue也是一個無界隊列,因此往隊列中插入數據的操作(生產者)永遠不會被阻塞,而只有獲取數據的操作(消費者)才會被阻塞。

阻塞隊列包括了非阻塞隊列中的大部分方法,還提供另外若干非常有用的方法:

put方法用來向隊尾存入元素,如果隊列滿,則等待;
take方法用來從隊首取元素,如果隊列為空,則等待;
offer方法用來向隊尾存入元素,如果隊列滿,則等待一定的時間,當時間期限達到時,如果還沒有插入成功,則返回false;否則返回true;
poll方法用來從隊首取元素,如果隊列空,則等待一定的時間,當時間期限達到時,如果取到,則返回null;否則返回取得的元素;

下面看一段代碼:

import java.util.concurrent.ArrayBlockingQueue;/**  * @author 作者:徐劍  E-mail:anxu_2013@163.com  * @version 創建時間:2016年3月20日 下午12:52:53  * 類說明  */public class BlockingQueue{  public static void main(String[] args) throws InterruptedException  {    java.util.concurrent.BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(5);    for (int i = 0; i < 10; i++)    {      // 將指定元素添加到此隊列中      blockingQueue.put("加入元素" + i);      System.out.println("向阻塞隊列中添加了元素:" + i);    }    System.out.println("程序到此運行結束,即將退出----");  }}

  當限制阻塞隊列數量為5時,添加了5個元素之后,繼續添加將會隊列外阻塞等待,此時程序并未終止。

  

  當隊列滿了之后,我們將隊首元素移除,則可以繼續向阻塞隊列中添加元素,代碼如下:

public class BlockingQueue{  public static void main(String[] args) throws InterruptedException  {    java.util.concurrent.BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(5);    for (int i = 0; i < 10; i++)    {      // 將指定元素添加到此隊列中      blockingQueue.put("加入元素" + i);      System.out.println("向阻塞隊列中添加了元素:" + i);      if(i>=4)        System.out.println("移除隊首元素"+blockingQueue.take());    }    System.out.println("程序到此運行結束,即將退出----");  }

  執行結果如下:

  

3、阻塞隊列的實現原理
  下面主要看一下ArrayBlockingQueue的實現原理。

  首先看一下ArrayBlockingQueue類的成員變量:

public class ArrayBlockingQueue<E> extends AbstractQueue<E>    implements BlockingQueue<E>, java.io.Serializable {  /** 底層存儲結構-數組 */  final Object[] items;  /** 隊首元素下標 */  int takeIndex;  /** 隊尾元素下標 */  int putIndex;  /**隊列元素總數 */  int count;  /** 重入鎖 */  final ReentrantLock lock;  /** notEmpty等待條件 */  private final Condition notEmpty;  /** notFull等待條件 */  private final Condition notFull;  /**   * Shared state for currently active iterators, or null if there   * are known not to be any. Allows queue operations to update   * iterator state.   */  transient Itrs itrs = null;

可以看到,ArrayBlockingQueue用來存儲元素的實際上是一個數組。

再看下ArrayBlockingQueue兩個重要方法的實現,put()和take():

public void put(E e) throws InterruptedException  {    //先檢查e是否為空    checkNotNull(e);    //獲取鎖    final ReentrantLock lock = this.lock;    lock.lockInterruptibly();    try    {      //當隊列已滿,進入條件等待      while (count == items.length)        notFull.await();      //隊列不滿,進行入隊列操作      enqueue(e);    }     finally    {      //釋放鎖      lock.unlock();    }  }

再看下具體的入隊操作:

private void enqueue(E x)  {    final Object[] items = this.items;    //隊尾入隊    items[putIndex] = x;    if (++putIndex == items.length)      putIndex = 0;    //隊列總數+1    count++;    //notempty條件的等待集中隨機選擇一個線程,解除其阻塞狀態    notEmpty.signal();  }

下面是take()方法的源代碼:

public E take() throws InterruptedException  {    //獲取鎖    final ReentrantLock lock = this.lock;    lock.lockInterruptibly();    try    {      //隊列為空      while (count == 0)        //線程加入notEmpty條件等待集        notEmpty.await();      //非空,出隊列      return dequeue();    } finally    {      //釋放鎖      lock.unlock();    }  }

4、阻塞隊列的應用:實現消費者-生產者模式

/**  * @author 作者:徐劍  E-mail:anxu_2013@163.com  * @version 創建時間:2016年3月20日 下午2:21:55  * 類說明:阻塞隊列實現的消費者-生產者模式 */public class Test{  private int queueSize = 10;  private ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(queueSize);  public static void main(String[] args)  {    Test test = new Test();    Producer producer = test.new Producer();    Consumer consumer = test.new Consumer();    producer.start();    consumer.start();  }  class Consumer extends Thread  {    @Override    public void run()    {      consume();    }    private void consume()    {      while (true)      {        try        {          queue.take();          System.out.println("從隊列取走一個元素,隊列剩余" + queue.size() + "個元素");        } catch (InterruptedException e)        {          e.printStackTrace();        }      }    }  }  class Producer extends Thread  {    @Override    public void run()    {      produce();    }    private void produce()    {      while (true)      {        try        {          queue.put(1);          System.out.println("向隊列取中插入一個元素,隊列剩余空間:"+ (queueSize - queue.size()));        } catch (InterruptedException e)        {          e.printStackTrace();        }      }    }  }}

以上就是本文的全部內容,希望對大家的學習有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 米林县| 大庆市| 和林格尔县| 敦化市| 垦利县| 游戏| 蒲江县| 亚东县| 宁蒗| 博湖县| 洛扎县| 武邑县| 福建省| 墨脱县| 孟津县| 静海县| 内黄县| 扶风县| 泰顺县| 独山县| 双桥区| 大化| 祁阳县| 望谟县| 桃园市| 台州市| 宝山区| 西乌珠穆沁旗| 固镇县| 棋牌| 枝江市| 苏尼特右旗| 承德县| 北海市| 西丰县| 安平县| 民勤县| 桑日县| 中牟县| 汝南县| 沙洋县|