首先放上一個類圖(jdk8)
下邊是根據上邊的基礎拓展出來的幾個對象,可以用executors直接生成,因爲如果用threadpoolexecutor,那麼有7個參數可以進行初始化:
int corePoolSize,(核心線程數量)
int maximumPoolSize,(最大線程數量),如果核心線程數量滿了,並且任務隊列排滿了,那麼就會新建線程直到最大線程數量
long keepAliveTime,(超過核心線程數量的線程存活時間)
TimeUnit unit,(超過核心線程數量的線程存活時間單位)
BlockingQueue workQueue,(任務隊列)
ThreadFactory threadFactory,(線程工廠)
RejectedExecutionHandler handler(拒絕策略),如果隊列滿了,並且已經到達了最大線程數量,那麼再加入任務就會執行拒絕策略
Executors類
在上邊的基礎上,我們可以從Executors中得到幾個線程池類型,這樣只需要填寫關鍵參數就行了
提供的有
newFixedThreadPool:固定線程數量的線程池
newSingleThreadExecutor:只有單一線程的線程池
newCachedThreadPool:緩存線程池
newScheduledThreadPool:定時任務線程池
加深練習
下邊是聽課時一個老師寫的一個練習類,可以供大家參考加深學習
/** 線程池的使用 */
public class ThreadPool {
/**
* 測試: 提交15個執行時間需要3秒的任務,看線程池的狀況
*
* @param threadPoolExecutor 傳入不同的線程池,看不同的結果
* @throws Exception
*/
public void testCommon(ThreadPoolExecutor threadPoolExecutor) throws Exception {
// 測試: 提交15個執行時間需要3秒的任務,看超過大小的2個,對應的處理情況
for (int i = 0; i < 15; i++) {
int n = i;
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println("開始執行:" + n);
Thread.sleep(3000L);
System.err.println("執行結束:" + n);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
System.out.println("任務提交成功 :" + i);
}
// 查看線程數量,查看隊列等待數量
Thread.sleep(500L);
System.out.println("當前線程池線程數量爲:" + threadPoolExecutor.getPoolSize());
System.out.println("當前線程池等待的數量爲:" + threadPoolExecutor.getQueue().size());
// 等待15秒,查看線程數量和隊列數量(理論上,會被超出核心線程數量的線程自動銷燬)
Thread.sleep(15000L);
System.out.println("當前線程池線程數量爲:" + threadPoolExecutor.getPoolSize());
System.out.println("當前線程池等待的數量爲:" + threadPoolExecutor.getQueue().size());
}
/**
* 1、線程池信息: 核心線程數量5,最大數量10,無界隊列,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略的
*
* @throws Exception
*/
private void threadPoolExecutorTest1() throws Exception {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>());
testCommon(threadPoolExecutor);
// 預計結果:線程池線程數量爲:5,超出數量的任務,其他的進入隊列中等待被執行
}
/**
* 2、 線程池信息: 核心線程數量5,最大數量10,隊列大小3,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略的
*
* @throws Exception
*/
private void threadPoolExecutorTest2() throws Exception {
// 創建一個 核心線程數量爲5,最大數量爲10,等待隊列最大是3 的線程池,也就是最大容納13個任務。
// 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.err.println("有任務被拒絕執行了");
}
});
testCommon(threadPoolExecutor);
// 預計結果:
// 1、 5個任務直接分配線程開始執行
// 2、 3個任務進入等待隊列
// 3、 隊列不夠用,臨時加開5個線程來執行任務(5秒沒活幹就銷燬)
// 4、 隊列和線程池都滿了,剩下2個任務,沒資源了,被拒絕執行。
// 5、 任務執行,5秒後,如果無任務可執行,銷燬臨時創建的5個線程
}
/**
* 3、 線程池信息: 核心線程數量5,最大數量5,無界隊列,超出核心線程數量的線程存活時間:5秒
*
* @throws Exception
*/
private void threadPoolExecutorTest3() throws Exception {
// 和Executors.newFixedThreadPool(int nThreads)一樣的
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
testCommon(threadPoolExecutor);
// 預計結:線程池線程數量爲:5,超出數量的任務,其他的進入隊列中等待被執行
}
/**
* 4、 線程池信息:
* 核心線程數量0,最大數量Integer.MAX_VALUE,SynchronousQueue隊列,超出核心線程數量的線程存活時間:60秒
*
* @throws Exception
*/
private void threadPoolExecutorTest4() throws Exception {
// SynchronousQueue,實際上它不是一個真正的隊列,因爲它不會爲隊列中元素維護存儲空間。與其他隊列不同的是,它維護一組線程,這些線程在等待着把元素加入或移出隊列。
// 在使用SynchronousQueue作爲工作隊列的前提下,客戶端代碼向線程池提交任務時,
// 而線程池中又沒有空閒的線程能夠從SynchronousQueue隊列實例中取一個任務,
// 那麼相應的offer方法調用就會失敗(即任務沒有被存入工作隊列)。
// 此時,ThreadPoolExecutor會新建一個新的工作者線程用於對這個入隊列失敗的任務進行處理(假設此時線程池的大小還未達到其最大線程池大小maximumPoolSize)。
// 和Executors.newCachedThreadPool()一樣的
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
testCommon(threadPoolExecutor);
// 預計結果:
// 1、 線程池線程數量爲:15,超出數量的任務,其他的進入隊列中等待被執行
// 2、 所有任務執行結束,60秒後,如果無任務可執行,所有線程全部被銷燬,池的大小恢復爲0
Thread.sleep(60000L);
System.out.println("60秒後,再看線程池中的數量:" + threadPoolExecutor.getPoolSize());
}
/**
* 5、 定時執行線程池信息:3秒後執行,一次性任務,到點就執行 <br/>
* 核心線程數量5,最大數量Integer.MAX_VALUE,DelayedWorkQueue延時隊列,超出核心線程數量的線程存活時間:0秒
*
* @throws Exception
*/
private void threadPoolExecutorTest5() throws Exception {
// 和Executors.newScheduledThreadPool()一樣的
ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
threadPoolExecutor.schedule(new Runnable() {
@Override
public void run() {
System.out.println("任務被執行,現在時間:" + System.currentTimeMillis());
}
}, 3000, TimeUnit.MILLISECONDS);
System.out.println(
"定時任務,提交成功,時間是:" + System.currentTimeMillis() + ", 當前線程池中線程數量:" + threadPoolExecutor.getPoolSize());
// 預計結果:任務在3秒後被執行一次
}
/**
* 6、 定時執行線程池信息:線程固定數量5 ,<br/>
* 核心線程數量5,最大數量Integer.MAX_VALUE,DelayedWorkQueue延時隊列,超出核心線程數量的線程存活時間:0秒
*
* @throws Exception
*/
private void threadPoolExecutorTest6() throws Exception {
ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
// 週期性執行某一個任務,線程池提供了兩種調度方式,這裏單獨演示一下。測試場景一樣。
// 測試場景:提交的任務需要3秒才能執行完畢。看兩種不同調度方式的區別
// 效果1: 提交後,2秒後開始第一次執行,之後每間隔1秒,固定執行一次(如果發現上次執行還未完畢,則等待完畢,完畢後立刻執行)。
// 也就是說這個代碼中是,3秒鐘執行一次(計算方式:每次執行三秒,間隔時間1秒,執行結束後馬上開始下一次執行,無需等待)
threadPoolExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任務-1 被執行,現在時間:" + System.currentTimeMillis());
}
}, 2000, 1000, TimeUnit.MILLISECONDS);
// 效果2:提交後,2秒後開始第一次執行,之後每間隔1秒,固定執行一次(如果發現上次執行還未完畢,則等待完畢,等上一次執行完畢後再開始計時,等待1秒)。
// 也就是說這個代碼鐘的效果看到的是:4秒執行一次。 (計算方式:每次執行3秒,間隔時間1秒,執行完以後再等待1秒,所以是 3+1)
threadPoolExecutor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任務-2 被執行,現在時間:" + System.currentTimeMillis());
}
}, 2000, 1000, TimeUnit.MILLISECONDS);
}
/**
* 7、 終止線程:線程池信息: 核心線程數量5,最大數量10,隊列大小3,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略的
*
* @throws Exception
*/
private void threadPoolExecutorTest7() throws Exception {
// 創建一個 核心線程數量爲5,最大數量爲10,等待隊列最大是3 的線程池,也就是最大容納13個任務。
// 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.err.println("有任務被拒絕執行了");
}
});
// 測試: 提交15個執行時間需要3秒的任務,看超過大小的2個,對應的處理情況
for (int i = 0; i < 15; i++) {
int n = i;
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println("開始執行:" + n);
Thread.sleep(3000L);
System.err.println("執行結束:" + n);
} catch (InterruptedException e) {
System.out.println("異常:" + e.getMessage());
}
}
});
System.out.println("任務提交成功 :" + i);
}
// 1秒後終止線程池
Thread.sleep(1000L);
threadPoolExecutor.shutdown();
// 再次提交提示失敗
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
System.out.println("追加一個任務");
}
});
// 結果分析
// 1、 10個任務被執行,3個任務進入隊列等待,2個任務被拒絕執行
// 2、調用shutdown後,不接收新的任務,等待13任務執行結束
// 3、 追加的任務在線程池關閉後,無法再提交,會被拒絕執行
}
/**
* 8、 立刻終止線程:線程池信息: 核心線程數量5,最大數量10,隊列大小3,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略的
*
* @throws Exception
*/
private void threadPoolExecutorTest8() throws Exception {
// 創建一個 核心線程數量爲5,最大數量爲10,等待隊列最大是3 的線程池,也就是最大容納13個任務。
// 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.err.println("有任務被拒絕執行了");
}
});
// 測試: 提交15個執行時間需要3秒的任務,看超過大小的2個,對應的處理情況
for (int i = 0; i < 15; i++) {
int n = i;
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
try {
System.out.println("開始執行:" + n);
Thread.sleep(3000L);
System.err.println("執行結束:" + n);
} catch (InterruptedException e) {
System.out.println("異常:" + e.getMessage());
}
}
});
System.out.println("任務提交成功 :" + i);
}
// 1秒後終止線程池
Thread.sleep(1000L);
List<Runnable> shutdownNow = threadPoolExecutor.shutdownNow();
// 再次提交提示失敗
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
System.out.println("追加一個任務");
}
});
System.out.println("未結束的任務有:" + shutdownNow.size());
// 結果分析
// 1、 10個任務被執行,3個任務進入隊列等待,2個任務被拒絕執行
// 2、調用shutdownnow後,隊列中的3個線程不再執行,10個線程被終止
// 3、 追加的任務在線程池關閉後,無法再提交,會被拒絕執行
}
public static void main(String[] args) throws Exception {
// new Demo9().threadPoolExecutorTest1();
// new Demo9().threadPoolExecutorTest2();
// new Demo9().threadPoolExecutorTest3();
// new Demo9().threadPoolExecutorTest4();
// new Demo9().threadPoolExecutorTest5();
// new Demo9().threadPoolExecutorTest6();
// new Demo9().threadPoolExecutorTest7();
new Demo9().threadPoolExecutorTest8();
}
}