public class ThreadPoolExecutor extends AbstractExecutorService
ThreadPoolExecutor 繼承了ExecutorService接口的抽象實現類AbstractExecutorService,提供了四個構造方法供編碼者使用:
前面三個方法都是給定默認參數替代沒有傳遞的參數然後this調用最後一個滿參數的構造函數,源代碼如下:
- public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
- this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler);
- }
上面這個構造方法就提供了一個默認的線程工廠和一個默認的拒絕handler。
通過ThreadPoolExecutor的構造方法得到的線程池使用方法和Executors.newFixedThreadPool()方法得到的線程池使用方式是一樣的,你可以以ExecutorService來接收它,通過ExecutorService的sumbit()方法提交你要管理的線程。
這裏再解讀一下線程工廠和拒絕handler的源碼,首先從handler開始:
這裏的RejectedExecutionHandler是java的concurrent包下的一個接口,java對其提供了四種實現:
它的主要負責的是在線程池內的線程都處於工作狀態時,有新的任務提交進來的處理工作。
1.AbortPolicy 從名字上面就可以看到,Abort-捨棄、終止,直接設置提交進來的任務,但是它在捨棄前還拋出一個異常,這也是未提交策略參數時,使用的默認策略:
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- throw new RejectedExecutionException();
- }
- /**
- * The default rejected execution handler
- */
- private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
2.CallerRunsPolicy 這個策略是在線程池滿負荷時,將會一直重試將此線程任務添加到線程池中。注意,如果線程池採用此種策略,可能會導致佔用cpu的過多的時間進行重新添加操作,導致真正在線程池中需要執行的線程分不到cpu的時間片。
- /**
- * Executes task r in the caller's thread, unless the executor
- * has been shut down, in which case the task is discarded.
- * @param r the runnable task requested to be executed
- * @param e the executor attempting to execute this task
- */
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- if (!e.isShutdown()) {
- r.run();
- }
- }
3.DiscardPolicy 這個策略直接貼源碼吧
- /**
- * Does nothing, which has the effect of discarding task r.
- * @param r the runnable task requested to be executed
- * @param e the executor attempting to execute this task
- */
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- }
看見了嗎,註釋裏面大大的Does nothing。人家啥也不幹,方法體內就是空的。你任務沒了他都不給你提示。
4.DiscardOldestPolicy 這個策略和上面的類似,不過它是將線程池隊列最老一個任務槍斃,然後把這個任務拉進來
- /**
- * Obtains and ignores the next task that the executor
- * would otherwise execute, if one is immediately available,
- * and then retries execution of task r, unless the executor
- * is shut down, in which case task r is instead discarded.
- * @param r the runnable task requested to be executed
- * @param e the executor attempting to execute this task
- */
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- if (!e.isShutdown()) {
- e.getQueue().poll();
- e.execute(r);
- }
- }
以上爲Handle java提供的實現類的解答,如果這四種不滿足使用需求,希望處理方法更加複雜一點,比如將多出來的任務放到某個地方,等這邊線程池過了高峯再去處理的話,可以自己實現RejectedExecutionHandler接口,在rejectedExecution()方法體中寫入你需要的邏輯。
接下來看看線程工廠的源碼:
ThreadFactory也是concurrent包下的接口,貼下源碼和註釋:
- /**
- * An object that creates new threads on demand. Using thread factories
- * removes hardwiring of calls to {@link Thread#Thread(Runnable) new Thread},
- * enabling applications to use special thread subclasses, priorities, etc.
- *
- * <p>
- * The simplest implementation of this interface is just:
- * <pre>
- * class SimpleThreadFactory implements ThreadFactory {
- * public Thread newThread(Runnable r) {
- * return new Thread(r);
- * }
- * }
- * </pre>
- *
- * The {@link Executors#defaultThreadFactory} method provides a more
- * useful simple implementation, that sets the created thread context
- * to known values before returning it.
- * @since 1.5
- * @author Doug Lea
- */
- public interface ThreadFactory {
- /**
- * Constructs a new {@code Thread}. Implementations may also initialize
- * priority, name, daemon status, {@code ThreadGroup}, etc.
- *
- * @param r a runnable to be executed by new thread instance
- * @return constructed thread, or {@code null} if the request to
- * create a thread is rejected
- */
- Thread newThread(Runnable r);
- }
可以看到,接口內只有一個方法,newThread(),從名字和註釋都可以知道,主要功能就是創建一個新的線程。
ThreadPoolExecutor中的默認線程工廠是類Executors的一個內部類
- /**
- * The default thread factory
- */
- 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() {
- public final native void wait(long timeout) throws InterruptedException;
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; } }上面默認的線程工廠也就是在創建線程時,設置了線程的組,線程名和優先級。我們也可以自己去實現ThreadFactory類,創建線程。下次有機會補上代碼及測試。