Executors 返回的線程池對象的弊端如下:
- FixedThreadPool 和 SingleThreadPool : 允 許 的 請 求 隊 列 長 度 爲
Integer.MAX_VALUE,可能會堆積大量的請求,從而導致 OOM; - CachedThreadPool 和 ScheduledThreadPool : 允 許 的 創 建 線 程 數 量 爲
Integer.MAX_VALUE,可能會創建大量的線程,從而導致 OOM。
正例:
int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
int KEEP_ALIVE_TIME = 1;
TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>();
ExecutorService executorService = new ThreadPoolExecutor(NUMBER_OF_CORES, NUMBER_OF_CORES*2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT,
taskQueue, new BackgroundThreadFactory(), new DefaultRejectedExecutionHandler());
反例:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
線程池知識科普
(1)ThreadPoolExecutor
/**
* 本質上來說 線程池的執行邏輯其實真的很簡單:
* 如果當前線程池的線程個數小於CORE_POOL_SIZE 那麼有任務到來的時候 就直接創建一個線程 執行這個任務
* 如果當前線程池的線程個數已經到了CORE_POOL_SIZE這個極限,那麼新來的任務就會被放到workQueue中
* 如果workQueue裏面的任務已滿,且MAXIMUM_POOL_SIZE這個值大於CORE_POOL_SIZE,那麼此時線程池會繼續創建線程執行任務
* 如果workQueue滿了,且線程池的線程數量也已經達到了MAXIMUM_POOL_SIZE 那麼就會把任務丟給rejectedExecutionHandler 來處理
* 當線程池中的線程超過了CORE_POOL_SIZE的哪些線程 如果空閒時間到了KEEP_ALIVE_TIME 那麼就會自動銷燬
* 當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閒時間達到keepAliveTime也將關閉
*/
ExecutorService executorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS, workQueue, threadFactory, rejectedExecutionHandler);
(2)線程隊列workQueue
隊列就分爲兩種,一種是有界隊列,一種是無界隊列。他倆最大的區別是:
無界隊列可以一直往裏面丟任務,而有界隊列當發現到了隊列大小極限以後就直接拒絕新任務的到來了。
這裏面的坑就是 無界隊列你無限往裏面丟任務,如果任務執行的慢 有可能任務太多 就oom了。
- 直接提交隊列:使用的是SynchronousQueue類實現的隊列。
提交到這個隊列中的任務不會被真實的保存,而是立刻將新任務提交個線程執行,如果沒有空閒的線程,就會創建新的線程,如果線程數量達到線程池的最大線程數maximumPoolSize,那麼就會執行拒絕策略,任務執行被拒絕。
- 有界的任務隊列:
使用的是ArrayBlockingQueue類實現的隊列,按照“先進先出”算法處理任務,它的構造函數是:
public ArrayBlockingQueue(int capacity)
使用它必須設置一個最大容量參數,使用有界的任務隊列的線程池,當有任務提交後,如果當前線程池中的線程數小於corePoolSize,就會創建新的線程執行任務,如果任務提交後,當前線程池內線程數大於corePoolSize,就會把任務先放到有界任務隊列中,若隊列放滿後,再創建新線程執行任務,但總的線程數不會超過最大值maximumPoolSize。
- 無界的任務隊列:
使用的是LinkedBlockingQueue類實現,不需要事先制定大小,也是按照“先進先出”算法處理任務。無界隊列很好理解,就是和有界隊列相反,使用無界隊列的線程池,當有新任務提交時,如果線程池裏有空閒線程,就分配線程立刻執行任務,否則就把任務放到無界任務隊列中等待,如果線程池中一直沒有空閒線程,但是新的任務又一直不停的提交上來,那麼這些任務全部會被掛到等待隊列中,一直到內存全部消耗完。
- 優先任務隊列:
使用的是PriorityBlockingQueue類實現,它根據任務的優先級順序執行任務,是一個無界隊列,它沒有限制,在內存允許的情況下可以無限添加元素;它又是具有優先級的隊列,是通過構造函數傳入的對象來判斷,傳入的對象必須實現comparable接口。
public class Person implements Comparable<Person>{
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
public Person() {
}
@Override
public String toString() {
return this.id + ":" + this.name;
}
@Override
public int compareTo(Person person) {
return this.id > person.getId() ? 1 : ( this.id < person.getId() ? -1 :0);
}
}
public static void main(String[] args) throws InterruptedException {
PriorityBlockingQueue<Person> pbq = new PriorityBlockingQueue<>();
pbq.add(new Person(3,"person3"));
pbq.add(new Person(2,"person2"));
pbq.add(new Person(1,"person1"));
}
ps:技術交流,歡迎大家加入,做一個有組織的RD