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