前言:最近面試和手動建立執行緒池時都用到了阻塞佇列,不由得產生好奇,**一下原理
參考:目錄
第一章 基礎使用
第二章 實現原理
2.1 arrayblockingqueue
2.2 linkedblockingqueue
第三章 執行緒池中所之用的阻塞佇列
juc中實現乙個阻塞佇列一般都會實現blockingqueue介面,主要方法說明
網上說的主流的阻塞佇列實現有兩種,分別是arrayblockingqueue和linkedblockingqueue
基於陣列的阻塞佇列實現,其內部維護乙個定長的陣列,用於儲存佇列元素。執行緒阻塞的實現是通過reentrantlock來完成的,資料的插入與取出共用同乙個鎖,因此arrayblockingqueue並不能實現生產、消費同時進行。而且在建立arrayblockingqueue時,我們還可以控制物件的內部鎖是否採用公平鎖,預設採用非公平鎖。
可以看到只new了乙個reentrantlock,所以插入與取出公用乙個鎖。
public arrayblockingqueue(int capacity, boolean fair)
基於單向鍊錶的阻塞佇列實現,在初始化linkedblockingqueue的時候可以指定對立的大小,也可以不指定,預設類似乙個無限大小的容量(integer.max_value),不指佇列容量大小也是會有風險的,一旦資料生產速度大於消費速度,系統記憶體將有可能被消耗殆盡,因此要謹慎操作。另外linkedblockingqueue中用於阻塞生產者、消費者的鎖是兩個(鎖分離),因此生產與消費是可以同時進行的。
可以看到用了兩個reentrantlock鎖
private final reentrantlock takelock = new reentrantlock();
/** wait queue for waiting takes */
private final condition notempty = takelock.newcondition();
/** lock held by put, offer, etc */
private final reentrantlock putlock = new reentrantlock();
在建立執行緒池時我發現會傳入linkedbockingqueue阻塞佇列。
public static executorservice newfixedthreadpool(int nthreads)
然後我實驗了一下,發現當向執行緒池插入過量執行緒時並不會阻塞插入執行緒的佇列,具體**如下:
所以說加入額外的執行緒並沒有阻塞當前執行緒
class mytest implements runnable
@override
public void run() catch (interruptedexception e)
}}public class threadpooltest
threadpool.shutdown();
system.out.println("結束");}}
輸出:
heihei
當前執行到0
heihei
當前執行到1
heihei
heihei
當前執行到2
heihei
heihei
heihei
heihei
heihei
heihei
結束當前執行到3
當前執行到4
當前執行到5
當前執行到6
當前執行到7
當前執行到8
當前執行到9
process finished with exit code 0
鑑於上面的情況我看了一下原始碼,我發現呼叫的是阻塞佇列的offer的方法向阻塞佇列中加入執行緒的,根據3.1中列出的方法,所以不會阻塞當前執行緒,如果是put方法就會阻塞了。
public void execute(runnable command)
//可以看到是offer
if (isrunning(c) && workqueue.offer(command))
else if (!addworker(command, false))
reject(command);
}
JUC 阻塞佇列
什麼是阻塞佇列 阻塞佇列常用於生產者和消費者場景,生產者是向佇列裡新增元素的執行緒,消費者是從佇列裡獲取元素的執行緒。阻塞佇列就是生產者用來存放元素 消費者用來獲取元素的容器 為什麼要使用阻塞佇列 就是適用在不得不阻塞的場景如上面所說生產者 和 消費者場景中 要是佇列中為空 消費者不得不進行阻塞 佇...
juc 阻塞佇列BlockingQueue
阻塞佇列blockingqueue的方法分類 方法型別 丟擲異常 特殊值阻塞 超時插入 add e offer e put e offer e,time,unit 移除remove poll take poll time,unit 檢查element peek 不可用不可用 丟擲異常 當阻塞佇列滿時...
JUC學習 阻塞佇列
在這篇部落格中我們接觸的佇列都是非阻塞佇列,比如priorityqueue linkedlist linkedlist是雙向鍊錶,它實現了dequeue介面 阻塞佇列常用於執行緒池和生產者消費者的問題中 使用非阻塞佇列的時候有乙個很大問題就是 它不會對當前執行緒產生阻塞,那麼在面對類似消費者 生產者...