天天看點

線程池的初步認識(一)線程池的初步認識(一)

線程池的初步認識(一)

一、定義

  • 管理一組工作線程。

二、作用

  • 可以限制應用程式中同一時刻運作的線程數;
  • 可以應用在多線程伺服器上。

三、好處

  1. 降低資源消耗。通過重複利用已建立的線程降低線程建立和銷毀造成的消耗,比如記憶體;
  2. 提高響應速度。建立線程再到執行任務的額外時間,會延遲處理的請求;
  3. 提高線程的客觀理性。通過線程池,實作對線程的統一配置設定,調優和監控;比如可以避免無線建立線程引起的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 的差別

  1. 非常相似,這兩個接口都表示可以由線程或ExecutorService同時執行的任務。
  2. 不同之處是兩個接口内部執行的方法不同。
  • Runnable
    public interface Runnable {
        public void run();
    }           
  • public interface Callable{
        public Object call() throws Exception;
    }           
  • 可以看出,call()方法是有傳回值的,而且可以引發異常。run沒有傳回值,也不能引發異常(除非未經檢查的異常-RuntimeException的子類)。

3.如果執行的任務需要傳回結果,使用Callable。

(三)、兩種執行方法的差別

  1. execute 隻能送出Runnable類型的任務;submit 除了可以送出Runnable類型的任務外,還可以送出Callable類型。
  2. execute 直接抛出任務執行的異常,submit 會捕獲,可以通過傳回值Future的get方法将執行任務時的異常重新抛出。
  3. submit 的頂級接口是ExecutorService;execute 的頂級接口是 Executor;

六、擷取傳回結果

(一)、 兩種 invokeAny() 和 invokeAll()

(二)、 invokeAny

  1. 當任意一個任務得到結果後,會調用interrupt方法将其他的任務中斷;
  2. 部分任務失敗,會使用第一個成功的任務傳回的結果;
  3. 任務全部失敗了,抛出Execption,invokeAny 方法将抛出ExecutionException。

(三)、 invokeAll 傳回所有任務的執行結果,該方法的執行效果也是阻塞執行的,要把所有的結果都取回時再繼續向下執行。

七、關閉 ExectorService

shutdown()

  1. 停止接收新的任務并且等待已經送出的任務(包含送出正在執行和送出未執行)執行完成。在終止前允許執行以前送出的任務;

shutdownNow()

  1. 阻止等待任務的啟動并試圖停止目前正在執行的任務。不允許執行以前送出的任務。

awaitTermination()

  1. 接收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

歡迎關注公衆号,檢視更多内容 :

線程池的初步認識(一)線程池的初步認識(一)