在阿里巴巴的《Java開發手冊》中是這樣規定線程池的:
線程池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的讀者更加明確線程池的:
線程池不允許使用Executors 去創建,而是通過ThreadPoolExecutor 的方式創建的,這樣的處理方式程序員更加明確線程池的運行規則.避免資源耗盡的風險.
說明:Executors返回的線程池對象的弊端如下:
1)FixedThreadPool和SingleThreadPool:允許的請求隊列長度爲Integer.MAX_VALUE,可能會堆積大量請求,從而導致OOM
2) CachedThreadPool 和 ScheduledThreadPool: 允許的創建線程數量爲Integer.MAX_VALUE,可能會創建大量線程,從而到時OOM
其實當我們去看Executors的源碼會發現,Executors.newFixedThreadPool()、Executors.newSingleThreadExecutor()和Executors.newCachedThreadPool等方法的底層都是通過ThreadPoolExecutor 實現的.
public class Executors {
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
// 那構造器最全的參數舉例
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
// maximumPoolSize 必須大於0,且必須大於 corePoolSize
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
}
1. int corePoolSize : 標識線程池的常駐核心線程數.
如果等於0,則標識在沒有任何任務的時候,銷燬線程池.
如果大於0 ,即使沒有任務時,也會保證線程池的線程數量等於次值. 但需要注意的是,如果此值設置的比較小,
則會頻繁創建和銷燬線程
如果設置的比較大,則會浪費系統資源,所以程序要需要根據自己的實際業務來調整此值.
2. int maximumPoolSize :表示線程池在任務最多時,最大可以創建的線程數.
官方規定此值必須大於0,同時也必須大於 corePoolSize, 此值只有在任務比較多的時候,且不能存放在任 務隊列時,纔會用到.
3. long keepAliveTime: 表示線程的存活時間,當線程池空閒時並且超過了此時間,多餘的線程就會銷燬,直到線程池中的線程數量銷燬等於corePoolSize爲止.
如果 maximumPoolSize 等於corePoolSize,那麼線程池在空閒的時候,也不會銷燬任何線程.
4.TimeUnit unit : 表示存活時間的單位,它是配合keepAliveTime 參數共同使用的
5.BlockingQueue<Runnable> workQueue :表示線程池執行的任務隊列,當線程池的所有線程都在處理任務時,如果來了新任務會緩存到此任務隊列中排隊等待執行.
6.ThreadFactory threadFactory: 表示線程的創建工廠,這個參數一般用的比較少,我們通常在創建線程時不指定此參數,它會使用默認的線程創建工廠的方法來創建線程
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public static ThreadFactory defaultThreadFactory() {
return new DefaultThreadFactory();
}
// 默認的線程創建工廠,需要創建ThreadFactory
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
// 創建一個非守護線程
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
// 優先級設置爲默認值
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
7.RejectedExecutionHandler handler: 表示指定線程池的拒絕策略. 當線程池的任務已經在緩存隊列 workQueue 中存儲滿了之後,並且不能創建新的線程來執行此任務時,就會用到此拒絕策略,它屬於一種限流保護機制.
ThreadPoolExecutor 自帶了4中拒絕策略:
new ThreadPoolExecutor.AbortPolicy():終止策略,線程池會拋出異常並終止執行,它是默認的拒絕策略.
new ThreadPoolExecutor.CallerRunsPolicy():報任務提交給當前線程來執行
new ThreadPoolExecutor.DiscardPolicy(): 忽略此任務(最新的任務)
new ThreadPoolExecutor.DiscardOldestPolicy():忽略最早的任務(最先加入隊列的任務)
通過看源碼以上4種拒絕策略均實現了RejectedExecutionHandler ,因此要自定義拒絕策略:
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
也應該實現該接口就可以了