程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java並發編程之壅塞隊列詳解

Java並發編程之壅塞隊列詳解

編輯:關於JAVA

Java並發編程之壅塞隊列詳解。本站提示廣大學習愛好者:(Java並發編程之壅塞隊列詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是Java並發編程之壅塞隊列詳解正文


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:[email protected] 
 * @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:[email protected] 
 * @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();
        }
      }
    }
  }
}

以上就是本文的全體內容,願望對年夜家的進修有所贊助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved