線程池的初步認識(一)
一、定義
- 管理一組工作線程。
二、作用
- 可以限制應用程式中同一時刻運作的線程數;
- 可以應用在多線程伺服器上。
三、好處
- 降低資源消耗。通過重複利用已建立的線程降低線程建立和銷毀造成的消耗,比如記憶體;
- 提高響應速度。建立線程再到執行任務的額外時間,會延遲處理的請求;
- 提高線程的客觀理性。通過線程池,實作對線程的統一配置設定,調優和監控;比如可以避免無線建立線程引起的OutOfMemoryError。
四、java 5 在 java.util.concurrent 中内置線程池 Excutors,傳回對象為ThreadPoolExecutor,包含三種建立的方法:
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
ExecutorService executorService2 = Executors.newFixedThreadPool(10);
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);
五、執行
(一)、 通過execute
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("我要開始運作了");
}
});
(二)、 通過submit
1.通過送出Runnable
Future future = executorService.submit(()->{
});
2.通過送出Callable
Future future = executorService.submit(() -> {
return null;
});
Runnable 和 Callable 的差別
- 非常相似,這兩個接口都表示可以由線程或ExecutorService同時執行的任務。
- 不同之處是兩個接口内部執行的方法不同。
- Runnable
public interface Runnable { public void run(); }
-
public interface Callable{ public Object call() throws Exception; }
- 可以看出,call()方法是有傳回值的,而且可以引發異常。run沒有傳回值,也不能引發異常(除非未經檢查的異常-RuntimeException的子類)。
3.如果執行的任務需要傳回結果,使用Callable。
(三)、兩種執行方法的差別
- execute 隻能送出Runnable類型的任務;submit 除了可以送出Runnable類型的任務外,還可以送出Callable類型。
- execute 直接抛出任務執行的異常,submit 會捕獲,可以通過傳回值Future的get方法将執行任務時的異常重新抛出。
- submit 的頂級接口是ExecutorService;execute 的頂級接口是 Executor;
六、擷取傳回結果
(一)、 兩種 invokeAny() 和 invokeAll()
(二)、 invokeAny
- 當任意一個任務得到結果後,會調用interrupt方法将其他的任務中斷;
- 部分任務失敗,會使用第一個成功的任務傳回的結果;
- 任務全部失敗了,抛出Execption,invokeAny 方法将抛出ExecutionException。
(三)、 invokeAll 傳回所有任務的執行結果,該方法的執行效果也是阻塞執行的,要把所有的結果都取回時再繼續向下執行。
七、關閉 ExectorService
shutdown()
- 停止接收新的任務并且等待已經送出的任務(包含送出正在執行和送出未執行)執行完成。在終止前允許執行以前送出的任務;
shutdownNow()
- 阻止等待任務的啟動并試圖停止目前正在執行的任務。不允許執行以前送出的任務。
awaitTermination()
-
接收timeout和TimeUnit兩個參數,用于設定逾時時間及機關。當等待超過設定時間時,會監測ExecutorService是否已經
關閉,若關閉則傳回true,否則傳回false。一般情況下會和shutdown方法組合使用。
在實際使用過程中, 使用shutdown()關閉,回收資源。如果有必要,可以在其後執行shutdownNow(),取消所有遺留的任務。
八、例子
ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(() -> {
return "Task 1";
}
});
callables.add(() -> {
return "Task 2";
}
});
List<Future<String>> futures = executorService.invokeAll(callables);
for(Future<String> future : futures){
System.out.println("future.get = " + future.get());
}
executorService.shutdown();
while (!service.awaitTermination(1, TimeUnit.SECONDS)) {
System.out.println("線程池沒有關閉");
}
github部落格清單位址
github歡迎關注公衆号,檢視更多内容 :
