簡介
我們在了解完線程池的參數配置和常用線程池后發現,每種線程池會根據不同的需求去選擇不同的隊列來存儲線程任務。線程池的對應隊列如下:

可以看到,五大常用的線程池,會用到三種線程池
LinkedBlockingQueue
LinkedBlockingQueue是一種沒有容量上限的隊列,也就是說,用了這個隊列的線程池,就可以沒有上限的去保存隊列任務。這種需求場景就很符合FixedThreadPool和SingleThreadExecutor,這兩種線程池都有一個相同點,那就是核心線程數和最大線程數是一致的,線程數都固定了,當任務多的時候線程處理不過來的線程就會放到隊列中,這時就需要一個沒有上限的隊列來存儲線程池的任務了。
SynchronousQueue
SynchronousQueue內部結構中沒有存儲隊列的容器,因此沒有辦法去存儲隊列消息,那么就會有人想,不能存儲消息那算哪門子隊列是吧,其實隊列不一定需要會存儲消息,SynchronousQueue雖然不能存儲隊列消息,但是他可以阻塞隊列消息,可以很好的完成中轉消息的用處,接下來我們可以參考下面這段代碼
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("生產者開始生產消息...");
String msg = "這是第"+(++i)+"條消息";
try {
int seconds = getRandomSeconds();
System.out.println("生產者生產消息花費了"+seconds+"秒");
TimeUnit.SECONDS.sleep(seconds);
queue.put(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生產者消息生產完畢...");
}
});
Thread consumer = new Thread(()->{
while (true){
System.out.println("消費者開始消費消息...");
try {
System.out.println("消費者消費到消息:"+queue.take());
int seconds = getRandomSeconds();
System.out.println("消費者消費消息花費了"+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;
}
}
生產者會隨機1到10秒去生產消息,消費者也會隨機1到10秒去消費消息,如果當遇到生產者正在生產消息的時候,消費者端就會因為沒有消息消費而阻塞在那里,同理,如果消費者正在消費消息,生產者也會因為隊列沒法存儲消息而阻塞在那里。
像這種場景就很適合CachedThreadPool這樣的線程池,因為CachedThreadPool可以創建的線程數是無限的,也就是說在這個線程池里面,任務隊列能不能存儲消息其實已經變的可有可無了,但是為了提高線程隊列中轉消息的性能,SynchronousQueue就變的更加合適,因為他想對於LinkedBlockingQueue,SynchronousQueue少了去存儲消息的性能消耗,自然的性能就增加了。
DelayedWorkQueue
DelayedWorkQueue的數據結構是采用數組來實現堆,並且內部元素並不是按照放入的時間順序來排序的,而是會按照延遲的時間長短對任務進行排序。我們可以看到ScheduledThreadPool和SingleThreadScheduledExecutor都適用DelayedWorkQueue來存放隊列,其實就是因為他可以按延遲時間長短排序任務執行的特性,來實現線程池定時的功能。
