ThreadPoolExecutor以內部線程池的形式對外提供管理任務執行,線程調度,線程池管理等等服務。
ThreadPoolExecutor構造方法解析
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {}
參數名 | 作用 |
---|---|
corePoolSize | 核心線程池大小 |
maximumPoolSize | 最大線程池大小 |
keepAliveTime | 線程池中超過corePoolSize數目的空閒線程最大存活時間 |
TimeUnit | keepAliveTime時間單位 |
workQueue | 阻塞任務隊列 |
threadFactory | 新建線程工廠 |
RejectedExecutionHandler | 當提交任務數超過maximumPoolSize+workQueue之和時,任務會交給RejectedExecutionHandler來處理 |
重點講解:
- 當線程池小於corePoolSize時,新提交任務將創建一個新線程執行任務,即使此時線程池中存在空閒線程。
- 當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行
- 當workQueue已滿,且maximumPoolSize>corePoolSize時,新提交任務會創建新線程執行任務
- 當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理
- 當線程池中超過corePoolSize線程,空閒時間達到keepAliveTime時,關閉空閒線程
- 當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閒時間達到keepAliveTime也將關閉
Executors提供靜態方法方便我們構造出線程池,不建議使用Executors,而直接使用ThreadPoolExecutor,更能加深這些參數是什麼意思,也能更好的構造出我們想要的線程池。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
構造一個固定線程數目的線程池,配置的corePoolSize與maximumPoolSize大小相同,同時使用了一個無界LinkedBlockingQueue存放阻塞任務,因此多餘的任務將存在再阻塞隊列,不會由RejectedExecutionHandler處理
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
構造一個緩衝功能的線程池,配置corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,以及一個無容量的阻塞隊列 SynchronousQueue,因此任務提交之後,將會創建新的線程執行;線程空閒超過60s將會銷燬
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
構造一個只支持一個線程的線程池,配置corePoolSize=maximumPoolSize=1,無界阻塞隊列LinkedBlockingQueue;保證任務由一個線程串行執行
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
}
構造有定時功能的線程池,配置corePoolSize,無界延遲阻塞隊列DelayedWorkQueue;有意思的是:maximumPoolSize=Integer.MAX_VALUE,由於DelayedWorkQueue是無界隊列,所以這個值是沒有意義的。
說ScheduledThreadPoolExecutor之前,先來看看Timer。
package com.koma.demo;
import java.util.Timer;
import java.util.TimerTask;
/**
* @author koma
* @version 2017年12月8日 下午1:55:06
*/
public class OutOfTime {
public static void main(String[] args) throws InterruptedException {
Timer timer=new Timer();
timer.schedule(new ThrowTask(), 1);
Thread.sleep(1000L);
timer.schedule(new ThrowTask(), 1);
Thread.sleep(5000L);
}
}
class ThrowTask extends TimerTask{
@Override
public void run() {
throw new RuntimeException();
}
}
結果:
Exception in thread "Timer-0" java.lang.RuntimeException
at com.koma.demo.ThrowTask.run(OutOfTime.java:24)
at java.util.TimerThread.mainLoop(Unknown Source)
at java.util.TimerThread.run(Unknown Source)
Exception in thread "main" java.lang.IllegalStateException: Timer already cancelled.
at java.util.Timer.sched(Unknown Source)
at java.util.Timer.schedule(Unknown Source)
at com.koma.demo.OutOfTime.main(OutOfTime.java:15)
你可能認爲程序運行6秒後退出,實際上並不是,並且拋出異常消息:Timer already cancelled。
package com.koma.demo;
import java.util.Timer;
import java.util.TimerTask;
/**
* @author koma
* @version 2017年12月8日 下午2:15:23
*/
public class TimerTest {
public static void main(String[] args) throws Exception {
TimerTask task1 = new TimerTask() {
@Override
public void run() {
System.out.println("task1: " + System.currentTimeMillis());
}
};
TimerTask task2 = new TimerTask() {
@Override
public void run() {
System.out.println("task2: " + System.currentTimeMillis());
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Timer timer = new Timer();
// 一秒鐘執行一次
timer.schedule(task1, 1, 1000);
timer.schedule(task2, 1);
}
}
結果:
task1: 1512714371122
task2: 1512714371122
task1: 1512714375122
task1: 1512714376122
task1: 1512714377122
task1: 1512714378122
從結果可看,task1本意是一秒鐘一次,但是第二次在四秒後才運行,丟失了三次。
Timer缺點:
- TimerTask拋出了一個未檢查的異常,Timer線程並不會捕獲異常,並且終止了定時線程。這種情況下,Timer也不會恢復線程的執行,而是錯誤的認爲整個Timer都被取消了。
- 某個週期TimerTask需要沒1000ms執行一次,而另一個Timertask需要執行4000ms,那麼週期任務或者在40ms任務執行完成後快速連續的調用3次,或者徹底丟失4次調用,取決於它是基於固定速率還是固定延時來調度。
ScheduledThreadPoolExecutor調度:
package com.koma.demo;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author koma
* @version 2017年12月8日 下午2:11:39
*/
public class ScheduledThreadPoolExecutorTest {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("task1: " + System.currentTimeMillis());
}
}, 1, 1000, TimeUnit.MILLISECONDS);
service.schedule(new Runnable() {
@Override
public void run() {
System.out.println("task2: " + System.currentTimeMillis());
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, 1, TimeUnit.MILLISECONDS);
}
}
結果:
task1: 1512715487934
task2: 1512715487934
task1: 1512715488934
task1: 1512715489934
task1: 1512715490934
task1: 1512715491934
由此可見task1就是1秒執行一次。
package com.koma.demo;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author koma
* @version 2017年12月8日 下午2:11:39
*/
public class ScheduledThreadPoolExecutorTest {
public static void main(String[] args) throws InterruptedException {
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
ScheduledThreadDemo t=new ScheduledThreadDemo();
Thread.sleep(1000L);
System.out.println(System.currentTimeMillis());
service.schedule(t, 1, TimeUnit.MILLISECONDS);
Thread.sleep(5000L);
service.schedule(t, 1, TimeUnit.MILLISECONDS);
System.out.println(System.currentTimeMillis());
service.shutdown();
}
}
class ScheduledThreadDemo implements Runnable{
@Override
public void run() {
throw new RuntimeException();
}
}
結果:
1512715983935
1512715988938
並沒有拋出異常。