閱讀了阿里JAVA開發手冊泰山版,其中關於線程池的創建有個強制要求:線程池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,這 樣的處理方式更加明確線程池的運行規則,規避資源耗盡的風險。
說明:Executors返回的線程池對象的弊端如下:
1)FixedThreadPool和SingtelThreadPool
允許的請求隊列長度爲 Integer.MAX_VALUE,可能會堆積大量的請求,從而導致 OOM。
2)CachedThreadPool
允許的創建線程數量爲 Integer.MAX_VALUE,可能會創建大量的線程,從而導致 OOM。
下面看看使用Executors創建線程的方式
1.創建CachedThreadPool
1.1 使用Executors創建
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
Executors的newCachedThreadPool()方法
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newCachedThreadPool()方法的第二個參數是線程池允許的最大線程數,使用該方法創建的線程池默認使用Integer.MAX_VALUE作爲線程池允許的最大線程數。所以使用該線程池時可能會創建大量的線程,從而導致內存溢出。
1.2 使用ThreadPoolExecutor,自定義參數創建
ThreadPoolExecutor cacheThreadPool = new ThreadPoolExecutor(10, 100, 60L,
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(true));
構建SynchronousQueue的參數fair表示創建的同步隊列是公平的還是不公平的,true則使用FIFO規則的隊列(Queue),false則使用棧(Stack)
public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}
2. 創建FixedThreadPool
2.1 使用Executors創建
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10);
Executors的newFixedThreadPool()方法
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
LinkedBlockingQueue默認創建的隊列沒有指定任務隊列的容量,使用默認容量Integer.MAX_VALUE,因此可能會堆積大量的任務,導致內存溢出。
同理SingleThreadExecutor。
3. ThreadPoolExecutor submit()和execute()執行任務的區別
- submit()方法是ThreadPoolExecutor父類AbstractExecutorService中實現的, 最後都會調用到AbstractExecutorService的實現類中的execute()方法。
- execute()方法是ThreadPoolExecutor實現的。
- submit()有返回值 Future,所以submit()方法執行任務是異步的。
- execute()沒有返回值,不是異步的。
AbstractExecutorService中的submit()方法
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask); // execute()在子類中實現
return ftask;
}
ThreadPoolExecutor中實現的execute()方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
僅供參考
關於阿里JAVA開發手冊泰山版,詳情點擊這裏免費下載。
說明:下載的手冊不得用作任何商業意圖,否則將依法追究相關法律責任,謹記。
如有侵權,請聯繫博主。