Queue接口與List Set同一級(jí)別 都是繼承了Collection接口 LinkedList實(shí)現(xiàn)了Queue接口 Queue接口窄化了對(duì)LinkedList的方法的訪(fǎng)問(wèn)權(quán)限(即在方法中的參數(shù)類(lèi)型如果是Queue時(shí) 就完全只能訪(fǎng)問(wèn)Queue接口所定義的方法了 而不能直接訪(fǎng)問(wèn) LinkedList的非Queue的方法) 以使得只有恰當(dāng)?shù)姆椒ú趴梢允褂?BlockingQueue 繼承了Queue接口
創(chuàng)新互聯(lián)建站是專(zhuān)業(yè)的峰峰礦網(wǎng)站建設(shè)公司,峰峰礦接單;提供成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專(zhuān)業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行峰峰礦網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專(zhuān)業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專(zhuān)業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu).它有兩個(gè)基本操作 在隊(duì)列尾部加人一個(gè)元素 和從隊(duì)列頭部移除一個(gè)元素就是說(shuō) 隊(duì)列以一種先進(jìn)先出的方式管理數(shù)據(jù) 如果你試圖向一個(gè)已經(jīng)滿(mǎn)了的阻塞隊(duì)列中添加一個(gè)元素或者是從一個(gè)空的阻塞隊(duì)列中移除一個(gè)元索 將導(dǎo)致線(xiàn)程阻塞.在多線(xiàn)程進(jìn)行合作時(shí) 阻塞隊(duì)列是很有用的工具 工作者線(xiàn)程可以定期地把中間結(jié)果存到阻塞隊(duì)列中而其他工作者線(xiàn)線(xiàn)程把中間結(jié)果取出并在將來(lái)修改它們 隊(duì)列會(huì)自動(dòng)平衡負(fù)載 如果第一個(gè)線(xiàn)程集運(yùn)行得比第二個(gè)慢 則第二個(gè)線(xiàn)程集在等待結(jié)果時(shí)就會(huì)阻塞 如果第一個(gè)線(xiàn)程集運(yùn)行得快 那么它將等待第二個(gè)線(xiàn)程集趕上來(lái) 下表顯示了jdk 中的阻塞隊(duì)列的操作
add??????? 增加一個(gè)元索???????????????????? 如果隊(duì)列已滿(mǎn) 則拋出一個(gè)IIIegaISlabEepeplian異常
remove?? 移除并返回隊(duì)列頭部的元素??? 如果隊(duì)列為空 則拋出一個(gè)NoSuchElementException異常
element? 返回隊(duì)列頭部的元素???????????? 如果隊(duì)列為空 則拋出一個(gè)NoSuchElementException異常
offer?????? 添加一個(gè)元素并返回true?????? 如果隊(duì)列已滿(mǎn) 則返回false
poll???????? 移除并返問(wèn)隊(duì)列頭部的元素??? 如果隊(duì)列為空 則返回null
peek?????? 返回隊(duì)列頭部的元素???????????? 如果隊(duì)列為空 則返回null
put???????? 添加一個(gè)元素????????????????????? 如果隊(duì)列滿(mǎn) 則阻塞
take??????? 移除并返回隊(duì)列頭部的元素???? 如果隊(duì)列為空 則阻塞
remove element offer poll peek 其實(shí)是屬于Queue接口
阻塞隊(duì)列的操作可以根據(jù)它們的響應(yīng)方式分為以下三類(lèi) aad removee和element操作在你試圖為一個(gè)已滿(mǎn)的隊(duì)列增加元素或從空隊(duì)列取得元素時(shí)拋出異常 當(dāng)然 在多線(xiàn)程程序中 隊(duì)列在任何時(shí)間都可能變成滿(mǎn)的或空的 所以你可能想使用offer poll peek方法 這些方法在無(wú)法完成任務(wù)時(shí)只是給出一個(gè)出錯(cuò)示而不會(huì)拋出異常
注意 poll和peek方法出錯(cuò)進(jìn)返回null 因此 向隊(duì)列中插入null值是不合法的
還有帶超時(shí)的offer和poll方法變種 例如 下面的調(diào)用
boolean success = q offer(x TimeUnit MILLISECONDS);
嘗試在 毫秒內(nèi)向隊(duì)列尾部插入一個(gè)元素 如果成功 立即返回true 否則 當(dāng)?shù)竭_(dá)超時(shí)進(jìn) 返回false 同樣地 調(diào)用
Object head = q poll( TimeUnit MILLISECONDS);
如果在 毫秒內(nèi)成功地移除了隊(duì)列頭元素 則立即返回頭元素 否則在到達(dá)超時(shí)時(shí) 返回null
最后 我們有阻塞操作put和take put方法在隊(duì)列滿(mǎn)時(shí)阻塞 take方法在隊(duì)列空時(shí)阻塞
ncurrent包提供了阻塞隊(duì)列的 個(gè)變種 默認(rèn)情況下 LinkedBlockingQueue的容量是沒(méi)有上限的(說(shuō)的不準(zhǔn)確 在不指定時(shí)容量為Integer MAX_VALUE 不要然的話(huà)在put時(shí)怎么會(huì)受阻呢) 但是也可以選擇指定其最大容量 它是基于鏈表的隊(duì)列 此隊(duì)列按 FIFO(先進(jìn)先出)排序元素
ArrayBlockingQueue在構(gòu)造時(shí)需要指定容量 并可以選擇是否需要公平性 如果公平參數(shù)被設(shè)置true 等待時(shí)間最長(zhǎng)的線(xiàn)程會(huì)優(yōu)先得到處理(其實(shí)就是通過(guò)將ReentrantLock設(shè)置為true來(lái)達(dá)到這種公平性的 即等待時(shí)間最長(zhǎng)的線(xiàn)程會(huì)先操作) 通常 公平性會(huì)使你在性能上付出代價(jià) 只有在的確非常需要的時(shí)候再使用它 它是基于數(shù)組的阻塞循環(huán)隊(duì)列 此隊(duì)列按 FIFO(先進(jìn)先出)原則對(duì)元素進(jìn)行排序
PriorityBlockingQueue是一個(gè)帶優(yōu)先級(jí)的隊(duì)列 而不是先進(jìn)先出隊(duì)列 元素按優(yōu)先級(jí)順序被移除 該隊(duì)列也沒(méi)有上限(看了一下源碼 PriorityBlockingQueue是對(duì)PriorityQueue的再次包裝 是基于堆數(shù)據(jù)結(jié)構(gòu)的 而PriorityQueue是沒(méi)有容量限制的 與ArrayList一樣 所以在優(yōu)先阻塞隊(duì)列上put時(shí)是不會(huì)受阻的 雖然此隊(duì)列邏輯上是無(wú)界的 但是由于資源被耗盡 所以試圖執(zhí)行添加操作可能會(huì)導(dǎo)致 OutOfMemoryError) 但是如果隊(duì)列為空 那么取元素的操作take就會(huì)阻塞 所以它的檢索操作take是受阻的 另外 往入該隊(duì)列中的元素要具有比較能力
最后 DelayQueue(基于PriorityQueue來(lái)實(shí)現(xiàn)的)是一個(gè)存放Delayed 元素的無(wú)界阻塞隊(duì)列 只有在延遲期滿(mǎn)時(shí)才能從中提取元素 該隊(duì)列的頭部是延遲期滿(mǎn)后保存時(shí)間最長(zhǎng)的 Delayed 元素 如果延遲都還沒(méi)有期滿(mǎn) 則隊(duì)列沒(méi)有頭部 并且poll將返回null 當(dāng)一個(gè)元素的 getDelay(TimeUnit NANOSECONDS) 方法返回一個(gè)小于或等于零的值時(shí) 則出現(xiàn)期滿(mǎn) poll就以移除這個(gè)元素了 此隊(duì)列不允許使用 null 元素 下面是延遲接口
Java代碼
public interface Delayed extends ComparableDelayed {
long getDelay(TimeUnit unit);
}
public interface Delayed extends ComparableDelayed {
long getDelay(TimeUnit unit);
}
放入DelayQueue的元素還將要實(shí)現(xiàn)pareTo方法 DelayQueue使用這個(gè)來(lái)為元素排序
下面的實(shí)例展示了如何使用阻塞隊(duì)列來(lái)控制線(xiàn)程集 程序在一個(gè)目錄及它的所有子目錄下搜索所有文件 打印出包含指定關(guān)鍵字的文件列表 從下面實(shí)例可以看出 使用阻塞隊(duì)列兩個(gè)顯著的好處就是 多線(xiàn)程操作共同的隊(duì)列時(shí)不需要額外的同步 另外就是隊(duì)列會(huì)自動(dòng)平衡負(fù)載 即那邊(生產(chǎn)與消費(fèi)兩邊)處理快了就會(huì)被阻塞掉 從而減少兩邊的處理速度差距 下面是具體實(shí)現(xiàn)
Java代碼
public class BlockingQueueTest {
public static void main(String[] args) {
Scanner in = new Scanner(System in);
System out print( Enter base directory (e g /usr/local/jdk /src): );
String directory = in nextLine();
System out print( Enter keyword (e g volatile): );
String keyword = in nextLine();
final int FILE_QUEUE_SIZE = ;// 阻塞隊(duì)列大小
final int SEARCH_THREADS = ;// 關(guān)鍵字搜索線(xiàn)程個(gè)數(shù)
// 基于ArrayBlockingQueue的阻塞隊(duì)列
BlockingQueueFile queue = new ArrayBlockingQueueFile(
FILE_QUEUE_SIZE);
//只啟動(dòng)一個(gè)線(xiàn)程來(lái)搜索目錄
FileEnumerationTask enumerator = new FileEnumerationTask(queue
new File(directory));
new Thread(enumerator) start();
//啟動(dòng) 個(gè)線(xiàn)程用來(lái)在文件中搜索指定的關(guān)鍵字
for (int i = ; i = SEARCH_THREADS; i++)
new Thread(new SearchTask(queue keyword)) start();
}
}
class FileEnumerationTask implements Runnable {
//啞元文件對(duì)象 放在阻塞隊(duì)列最后 用來(lái)標(biāo)示文件已被遍歷完
public static File DUMMY = new File( );
private BlockingQueueFile queue;
private File startingDirectory;
public FileEnumerationTask(BlockingQueueFile queue File startingDirectory) {
this queue = queue;
this startingDirectory = startingDirectory;
}
public void run() {
try {
enumerate(startingDirectory);
queue put(DUMMY);//執(zhí)行到這里說(shuō)明指定的目錄下文件已被遍歷完
} catch (InterruptedException e) {
}
}
// 將指定目錄下的所有文件以File對(duì)象的形式放入阻塞隊(duì)列中
public void enumerate(File directory) throws InterruptedException {
File[] files = directory listFiles();
for (File file : files) {
if (file isDirectory())
enumerate(file);
else
//將元素放入隊(duì)尾 如果隊(duì)列滿(mǎn) 則阻塞
queue put(file);
}
}
}
class SearchTask implements Runnable {
private BlockingQueueFile queue;
private String keyword;
public SearchTask(BlockingQueueFile queue String keyword) {
this queue = queue;
this keyword = keyword;
}
public void run() {
try {
boolean done = false;
while (!done) {
//取出隊(duì)首元素 如果隊(duì)列為空 則阻塞
File file = queue take();
if (file == FileEnumerationTask DUMMY) {
//取出來(lái)后重新放入 好讓其他線(xiàn)程讀到它時(shí)也很快的結(jié)束
queue put(file);
done = true;
} else
search(file);
}
} catch (IOException e) {
e printStackTrace();
} catch (InterruptedException e) {
}
}
public void search(File file) throws IOException {
Scanner in = new Scanner(new FileInputStream(file));
int lineNumber = ;
while (in hasNextLine()) {
lineNumber++;
String line = in nextLine();
if (ntains(keyword))
System out printf( %s:%d:%s%n file getPath() lineNumber
line);
}
in close();
}
lishixinzhi/Article/program/Java/hx/201311/26657
阻塞隊(duì)列與普通隊(duì)列的區(qū)別在于,當(dāng)隊(duì)列是空的時(shí),從隊(duì)列中獲取元素的操作將會(huì)被阻塞,或者當(dāng)隊(duì)列是滿(mǎn)時(shí),往隊(duì)列里添加元素的操作會(huì)被阻塞。試圖從空的阻塞隊(duì)列中獲取元素的線(xiàn)程將會(huì)被阻塞,直到其他的線(xiàn)程往空的隊(duì)列插入新的元素。同樣,試圖往已滿(mǎn)的阻塞隊(duì)列中添加新元素的線(xiàn)程同樣也會(huì)被阻塞,直到其他的線(xiàn)程使隊(duì)列重新變得空閑起來(lái),如從隊(duì)列中移除一個(gè)或者多個(gè)元素,或者完全清空隊(duì)列.
從5.0開(kāi)始,JDK在java.util.concurrent包里提供了阻塞隊(duì)列的官方實(shí)現(xiàn)。盡管JDK中已經(jīng)包含了阻塞隊(duì)列的官方實(shí)現(xiàn),但是熟悉其背后的原理還是很有幫助的。一下是阻塞隊(duì)列的實(shí)現(xiàn):
public?class?Ba?href=";tn=44039180_cprfenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y4rH6vrHP-m1b3myP-rA7B0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnHRYnjDsnWbdPHcvnj61P1RsPs"target="_blank"?class="baidu-highlight"lock/aingQueue?{
private?List?queue?=?new?LinkedList();
private?int??limit?=?10;
public?Ba?href=";tn=44039180_cprfenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y4rH6vrHP-m1b3myP-rA7B0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnHRYnjDsnWbdPHcvnj61P1RsPs"?target="_blank"?class="baidu-highlight"lock/aingQueue(int?limit){
this.limit?=?limit;
}
public?synchronized?void?enqueue(Object?item)
throws?InterruptedException??{
while(this.queue.size()?==?this.limit)?{
wait();
}
if(this.queue.size()?==?0)?{
notifyAll();
}
this.queue.add(item);
}
public?synchronized?Object?dequeue()
throws?InterruptedException{
while(this.queue.size()?==?0){
wait();
}
if(this.queue.size()?==?this.limit){
notifyAll();
}
return?this.queue.remove(0);
}
}
Java里的阻塞隊(duì)列有以下幾種:
ArrayBlockingQueue :一個(gè)由數(shù)組結(jié)構(gòu)組成的有界阻塞隊(duì)列。
LinkedBlockingQueue :一個(gè)由鏈表結(jié)構(gòu)組成的有界阻塞隊(duì)列。
PriorityBlockingQueue :一個(gè)支持優(yōu)先級(jí)排序的無(wú)界阻塞隊(duì)列。
DelayQueue:一個(gè)使用優(yōu)先級(jí)隊(duì)列實(shí)現(xiàn)的無(wú)界阻塞隊(duì)列。
SynchronousQueue:一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列。
LinkedTransferQueue:一個(gè)由鏈表結(jié)構(gòu)組成的無(wú)界阻塞隊(duì)列。
LinkedBlockingDeque:一個(gè)由鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列。