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(); } } } } }
以上就是本文的全體內容,願望對年夜家的進修有所贊助。