推薦:Java并發程式設計彙總
Java并發程式設計一如何關閉線程池
當線程池中已經有大量線程正在處理任務,并且任務隊列中也有很多任務正在等待被處理,這個時候我們該如何去關閉線程池呢?線程池的後續處理又是怎麼的呢?
首先我們來建立一個任務。
任務
ShutDownTask
類實作了
Runnable
接口,它的
run()
就是我們線程所要執行的任務,我們這裡的任務非常簡單,就是輸出自己(目前線程)的名稱,再
sleep(500)
即可。
class ShutDownTask implements Runnable {
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "被中斷了");
}
}
}
shutdown()
我們先來測試一下
shutdown()
的作用。
測試代碼:
package threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ShutDown {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executorService.execute(new ShutDownTask());
}
Thread.sleep(1000);
executorService.shutdown();
}
}
輸出
pool-1-thread-6
pool-1-thread-5
pool-1-thread-7
pool-1-thread-9
pool-1-thread-10
pool-1-thread-4
pool-1-thread-2
pool-1-thread-8
pool-1-thread-1
pool-1-thread-3
pool-1-thread-5
pool-1-thread-6
pool-1-thread-8
pool-1-thread-10
pool-1-thread-2
我隻粘貼了一部分輸出,其實會輸出
100
行,也就是線程池會處理完所有的任務,既包括正在執行的任務,還包括已經送出到任務隊列上的任務,我們從代碼也可以分析出來,每個任務會
sleep(500)
,而在
main
線程中送出任務後,隻
sleep(1000)
,而
main
線程
sleep(1000)
後,很顯然所有的任務是不可能已經被全部執行完的,而我們這裡定義的線程池是
FixedThreadPool
,它最多隻能存在
10
個線程去執行任務,是以肯定有任務在任務隊列中,而當
main
線程調用線程池的
shutdown()
後,所有任務依然全部執行完了,可以說明
shutdown()
會處理完所有的任務,既包括正在執行的任務,還包括已經送出到任務隊列上的任務。
可以得出,調用
shutdown()
後線程池的後續操作:
- 停止接收新
的任務。submit
- 已經送出的任務(包括正在執行的任務和隊列中等待的任務),都會繼續執行完成。
- 等到第
步完成後,才真正停止。2
shutdown()後線程池是否還能送出任務?
測試代碼:
package threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ShutDown {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executorService.execute(new ShutDownTask());
}
Thread.sleep(1000);
executorService.shutdown();
executorService.execute(new ShutDownTask());
}
}
很明顯是不能再送出任務的,線程池拒絕了送出的任務,之前說過,當線程池滿了(不能再建立線程去處理任務,即線程數為最大線程數
maximumPoolSize
,任務隊列也裝滿了任務)之後也會拒絕送出的任務,這裡又多了一種情況。
如果我們就想讓線程池現在、馬上、立刻就停止呢?接着看。
shutdownNow()
測試代碼:
package threadpool;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ShutDown {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executorService.execute(new ShutDownTask());
}
Thread.sleep(1000);
List<Runnable> runnableList = executorService.shutdownNow();
}
}
輸出:
pool-1-thread-8
pool-1-thread-4
pool-1-thread-2
pool-1-thread-3
pool-1-thread-1
pool-1-thread-6
pool-1-thread-7
pool-1-thread-9
pool-1-thread-10
pool-1-thread-5
pool-1-thread-3
pool-1-thread-1
pool-1-thread-2
pool-1-thread-4
pool-1-thread-8
pool-1-thread-5
pool-1-thread-6
pool-1-thread-10
pool-1-thread-7
pool-1-thread-9
pool-1-thread-2被中斷了
pool-1-thread-5被中斷了
pool-1-thread-3被中斷了
pool-1-thread-6被中斷了
pool-1-thread-4被中斷了
pool-1-thread-8被中斷了
pool-1-thread-1被中斷了
這是全部輸出了,很顯然正在執行的任務會被中斷執行,在任務隊列中的線程會被直接忽略。
Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
翻譯:嘗試停止所有正在執行的任務,停止處理等待的任務,并傳回等待執行任務的清單。
上面代碼中的
runnableList
就是等待執行任務的清單,以便程式可以做後續處理,如重新建立線程池去處理等。
調用此方法當然也會拒絕新送出的任務,大家可以自己去試一試,要多動手敲代碼,代碼才會認識你。
可以得出,調用
shutdownNow()
後線程池的後續操作:
- 跟
一樣,先停止接收新shutdown()
的任務。submit
- 忽略任務隊列裡等待的任務。
- 嘗試将正在執行的任務
中斷。interrupt
- 傳回未執行的任務清單。
線程池試圖終止線程的方法是通過調用
interrupt()
方法來實作的,這種方法的作用有限,如果線程中沒有
sleep
、
wait
、
Condition
、定時鎖等應用,
interrupt()
方法是無法中斷目前的線程的。是以,
shutdownNow()
并不代表線程池就一定立即能退出,它也可能必須要等待所有正在執行的任務都執行完成了才能退出。但是大多數時候是能立即退出的。
awaitTermination()
測試代碼:
package threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ShutDown {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executorService.execute(new ShutDownTask());
}
Thread.sleep(1500);
executorService.shutdown();
boolean b = executorService.awaitTermination(1L, TimeUnit.SECONDS);
System.out.println(b);
}
}
結果:
測試代碼:
package threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ShutDown {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executorService.execute(new ShutDownTask());
}
Thread.sleep(1500);
executorService.shutdown();
boolean b = executorService.awaitTermination(7L, TimeUnit.SECONDS);
System.out.println(b);
}
}
結果:
/**
* Blocks until all tasks have completed execution after a shutdown
* request, or the timeout occurs, or the current thread is
* interrupted, whichever happens first.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return {@code true} if this executor terminated and
* {@code false} if the timeout elapsed before termination
* @throws InterruptedException if interrupted while waiting
*/
- 所有已送出的任務(包括正在執行的任務和隊列中等待的任務)執行完。
- 逾時時間到了(
和 timeout
設定的時間)。TimeUnit
- 線程被中斷,抛出
。InterruptedException