Executors
Executors爲Executor,ExecutorService,ScheduledExecutorService,ThreadFactory和Callable類提供了一些工具方法,類似於集合中的Collections類的功能
- newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
功能:它將會爲每個任務創建一個線程,此線程池的最大值是Integer的最大值(2^31-1),60秒內可以重用已經創建的線程,如果線程池的大小超過了處理任務所需要的線程,那麼就會回收部分空閒的線程
適用:該線程池比較適合沒有固定大小並且比較快速就能完成的小任務
- newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
功能:創建固定大小的線程池。每次提交一個任務就創建一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,再提交新任務,任務將會進入等待隊列中等待。如果某個線程因爲執行異常而結束,那麼線程池會補充一個新線程
- newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
功能:創建一個單線程的線程池。也就是相當於單線程串行執行所有任務。如果這個唯一的線程因爲異常結束,那麼會有一個新的線程來替代,。此線程池保證所有任務的執行順序按照任務的提交順序執行
除了CachedThreadPool使用的是直接提交策略的緩衝隊列以外,其餘兩個採用的都是無界緩衝隊列
以上三種都使用ThreadPoolExecutor創建
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
corePoolSize:核心線程數量,小於corePoolSize都會直接創建線程
maximumPoolSize:最大線程數量,大於最大線程數量則由拒絕策略處理
keepAliveTime:線程最大空閒存活時間
unit:線程最大空閒存活時間單位
workQueue:緩衝隊列,超過任務超過corePoolSize大小後,放入workQueue隊列進行緩衝處理
threadFactory:線程工廠
defaultHandler:拒絕處理程序策略 默認AbortPolicy 拋出異常
拒絕處理程序策略
默認的ThreadPoolExecutor.AbortPolicy
處理程序遭到拒絕將拋出運行時RejectedExecutionException;
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
ThreadPoolExecutor.CallerRunsPolicy
調用excute任務本身的線程處理,主線程直接調用,如果執行程序已關閉,則會丟棄該任務
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
ThreadPoolExecutor.DiscardPolicy
不能執行的任務將被刪除;
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
ThreadPoolExecutor.DiscardOldestPolicy
如果執行程序尚未關閉,則位於工作隊列頭部的任務將被刪除,然後重試執行程序(如果再次失敗,則重複此過程)。
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
ThreadFactory
默認同一個 ThreadGroup 中一律使用 Executors.defaultThreadFactory() 創建線程,並且這些線程具有相同的 NORM_PRIORITY 優先級和非守護進程狀態。通過提供不同的 ThreadFactory,可以改變線程的名稱、線程組、優先級、守護進程狀態等等。
private 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;
}
}
ExecutorService執行方法:
- execute(Runnable)
這個方法接收一個Runnable實例,並且異步的執行,無法知道結果 - submit(Runnable)
這個方法接收一個Runnable實例,並且異步的執行,返回一個Future對象,可以檢查結果
Future future = executorService.submit(new MyRunnable);
//方法會阻塞,返回null表示執行成功
future.get();
- submit(Callable)
也會返回一個Future對象,但是除此之外,submit(Callable)接收的是一個Callable的實現,Callable接口中的call()方法有一個返回值,可以返回任務的執行結果
Future future = executorService.submit(new MyCallable());
//方法會阻塞,返回值爲Call()
future.get();
當我們使用完成ExecutorService之後應該關閉它,否則它裏面的線程會一直處於運行狀態。
舉個例子,如果的應用程序是通過main()方法啓動的,在這個main()退出之後,如果應用程序中的ExecutorService沒有關閉,這個應用將一直運行。之所以會出現這種情況,是因爲ExecutorService中運行的線程會阻止JVM關閉。
調用shutdown()方法之後,ExecutorService不會立即關閉,但是它不再接收新的任務,直到當前所有線程執行完成纔會關閉。
調用shutdownNow()方法。這個動作將跳過所有正在執行的任務和被提交還沒有執行的任務。但是它並不對正在執行的任務做任何保證,有可能它們都會停止,也有可能執行完成。
ScheduledExecutorService
定時任務線程池
- schedule (Runnable task, long delay, TimeUnit timeunit)
指定延遲之後運行task。這個方法有個問題,就是沒有辦法獲知task的執行結果。如果我們想獲得task的執行結果,我們可以傳入一個Callable的實例 - schedule (Callable task, long delay, TimeUnit timeunit)
這個方法與schedule (Runnable task)類似,也是在指定延遲之後運行task,不過它接收的是一個Callable實例,此方法會返回一個ScheduleFuture對象,通過ScheduleFuture我們可以取消一個未執行的task,也可以獲得這個task的執行結果 - scheduleAtFixedRate (Runnable, long initialDelay, long period, TimeUnit timeunit)
週期性的調度task執行。task第一次執行的延遲根據initialDelay參數確定,以後每一次執行都間隔period時長。
如果task的執行時間大於定義的period,那麼下一個線程將在當前線程完成之後再執行。整個調度保證不會出現一個以上任務同時執行 - scheduleWithFixedDelay (Runnable, long initialDelay, long period, TimeUnit timeunit)
與scheduleAtFixedRate類似,scheduleWithFixedDelay中,period指的當前任務的結束執行時間到下個任務的開始執行時間。