【線程池】常用的三種阻塞隊(duì)列
簡(jiǎn)介
我們?cè)诹私馔?a target="_blank" rel="noopener nofollow">線程池的參數(shù)配置和常用線程池后發(fā)現(xiàn),每種線程池會(huì)根據(jù)不同的需求去選擇不同的隊(duì)列來存儲(chǔ)線程任務(wù)。線程池的對(duì)應(yīng)隊(duì)列如下:

可以看到,五大常用的線程池,會(huì)用到三種線程池
LinkedBlockingQueue
LinkedBlockingQueue是一種沒有容量上限的隊(duì)列,也就是說,用了這個(gè)隊(duì)列的線程池,就可以沒有上限的去保存隊(duì)列任務(wù)。這種需求場(chǎng)景就很符合FixedThreadPool和SingleThreadExecutor,這兩種線程池都有一個(gè)相同點(diǎn),那就是核心線程數(shù)和最大線程數(shù)是一致的,線程數(shù)都固定了,當(dāng)任務(wù)多的時(shí)候線程處理不過來的線程就會(huì)放到隊(duì)列中,這時(shí)就需要一個(gè)沒有上限的隊(duì)列來存儲(chǔ)線程池的任務(wù)了。
SynchronousQueue
SynchronousQueue內(nèi)部結(jié)構(gòu)中沒有存儲(chǔ)隊(duì)列的容器,因此沒有辦法去存儲(chǔ)隊(duì)列消息,那么就會(huì)有人想,不能存儲(chǔ)消息那算哪門子隊(duì)列是吧,其實(shí)隊(duì)列不一定需要會(huì)存儲(chǔ)消息,SynchronousQueue雖然不能存儲(chǔ)隊(duì)列消息,但是他可以阻塞隊(duì)列消息,可以很好的完成中轉(zhuǎn)消息的用處,接下來我們可以參考下面這段代碼
public class SynchronousQueueDemo {
public static void main(String[] args) {
SynchronousQueue<String> queue = new SynchronousQueue<>();
Thread producer = new Thread(()->{
int i = 0;
while (true){
System.out.println("生產(chǎn)者開始生產(chǎn)消息...");
String msg = "這是第"+(++i)+"條消息";
try {
int seconds = getRandomSeconds();
System.out.println("生產(chǎn)者生產(chǎn)消息花費(fèi)了"+seconds+"秒");
TimeUnit.SECONDS.sleep(seconds);
queue.put(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生產(chǎn)者消息生產(chǎn)完畢...");
}
});
Thread consumer = new Thread(()->{
while (true){
System.out.println("消費(fèi)者開始消費(fèi)消息...");
try {
System.out.println("消費(fèi)者消費(fèi)到消息:"+queue.take());
int seconds = getRandomSeconds();
System.out.println("消費(fèi)者消費(fèi)消息花費(fèi)了"+seconds+"秒");
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
producer.start();
consumer.start();
}
private static int getRandomSeconds(){
Random random = new Random();
return random.nextInt(10)+1;
}
}
生產(chǎn)者會(huì)隨機(jī)1到10秒去生產(chǎn)消息,消費(fèi)者也會(huì)隨機(jī)1到10秒去消費(fèi)消息,如果當(dāng)遇到生產(chǎn)者正在生產(chǎn)消息的時(shí)候,消費(fèi)者端就會(huì)因?yàn)闆]有消息消費(fèi)而阻塞在那里,同理,如果消費(fèi)者正在消費(fèi)消息,生產(chǎn)者也會(huì)因?yàn)殛?duì)列沒法存儲(chǔ)消息而阻塞在那里。
像這種場(chǎng)景就很適合CachedThreadPool這樣的線程池,因?yàn)镃achedThreadPool可以創(chuàng)建的線程數(shù)是無限的,也就是說在這個(gè)線程池里面,任務(wù)隊(duì)列能不能存儲(chǔ)消息其實(shí)已經(jīng)變的可有可無了,但是為了提高線程隊(duì)列中轉(zhuǎn)消息的性能,SynchronousQueue就變的更加合適,因?yàn)樗雽?duì)于LinkedBlockingQueue,SynchronousQueue少了去存儲(chǔ)消息的性能消耗,自然的性能就增加了。
DelayedWorkQueue
DelayedWorkQueue的數(shù)據(jù)結(jié)構(gòu)是采用數(shù)組來實(shí)現(xiàn)堆,并且內(nèi)部元素并不是按照放入的時(shí)間順序來排序的,而是會(huì)按照延遲的時(shí)間長(zhǎng)短對(duì)任務(wù)進(jìn)行排序。我們可以看到ScheduledThreadPool和SingleThreadScheduledExecutor都適用DelayedWorkQueue來存放隊(duì)列,其實(shí)就是因?yàn)樗梢园囱舆t時(shí)間長(zhǎng)短排序任務(wù)執(zhí)行的特性,來實(shí)現(xiàn)線程池定時(shí)的功能。

浙公網(wǎng)安備 33010602011771號(hào)