線程池ThreadPoolExecutor的三種隊列區別

使用方法:

1.SynchronousQueue
 

private static ExecutorService cachedThreadPool = new ThreadPoolExecutor(4, Runtime.getRuntime().availableProcessors() * 2, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), r -> new Thread(r, "ThreadTest"));


SynchronousQueue沒有容量,是無緩衝等待隊列,是一個不存儲元素的阻塞隊列,會直接將任務交給消費者,必須等隊列中的添加元素被消費後才能繼續添加新的元素。

SynchronousQueue這種隊列,這種隊列的特點是不緩存數據,而是緩存線程,線程分爲生產者線程和消費者線程,一個生產者線程和一個消費者線程是互補的,當一個生產者線程遇到一個消費者線程的時候就會直接進行數據交換,所以這種隊列的技術點比較高,理解起來難度較大。一個線程只能緩存一個數據,當一個線程插入數據之後就會被阻塞,直到另外一個線程消費了其中的數據。

擁有公平(FIFO)和非公平(LIFO)策略,非公平側羅會導致一些數據永遠無法被消費的情況?

使用SynchronousQueue阻塞隊列一般要求maximumPoolSizes爲無界(Integer.MAX_VALUE),避免線程拒絕執行操作。

 

2.LinkedBlockingQueue
 

private static ExecutorService cachedThreadPool = new ThreadPoolExecutor(4, Runtime.getRuntime().availableProcessors() * 2, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), r -> new Thread(r, "ThreadTest"));


LinkedBlockingQueue是一個無界緩存等待隊列。當前執行的線程數量達到corePoolSize的數量時,剩餘的元素會在阻塞隊列裏等待。(所以在使用此阻塞隊列時maximumPoolSizes就相當於無效了),每個線程完全獨立於其他線程。生產者和消費者使用獨立的鎖來控制數據的同步,即在高併發的情況下可以並行操作隊列中的數據。

注:這個隊列需要注意的是,雖然通常稱其爲一個無界隊列,但是可以人爲指定隊列大小,而且由於其用於記錄隊列大小的參數是int類型字段,所以通常意義上的無界其實就是隊列長度爲 Integer.MAX_VALUE,且在不指定隊列大小的情況下也會默認隊列大小爲 Integer.MAX_VALUE,等同於如下:

private static ExecutorService cachedThreadPool = new ThreadPoolExecutor(4, Runtime.getRuntime().availableProcessors() * 2, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(Integer.MAX_VALUE), r -> new Thread(r, "ThreadTest"));


3.ArrayBlockingQueue

 private static ExecutorService cachedThreadPool = new ThreadPoolExecutor(4, Runtime.getRuntime().availableProcessors() * 2, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(32), r -> new Thread(r, "ThreadTest"));


ArrayBlockingQueue是一個有界緩存等待隊列,可以指定緩存隊列的大小,當正在執行的線程數等於corePoolSize時,多餘的元素緩存在ArrayBlockingQueue隊列中等待有空閒的線程時繼續執行,當ArrayBlockingQueue已滿時,加入ArrayBlockingQueue失敗,會開啓新的線程去執行,當線程數已經達到最大的maximumPoolSizes時,再有新的元素嘗試加入ArrayBlockingQueue時會報錯。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章