天天看點

Java 多線程(三)線程池入門 Callable 和 Future

Java 多線程 系列文章目錄:

  • Java 多線程(一)線程間的互斥和同步通信
  • Java 多線程(二)同步線程分組問題
  • Java 多線程(三)線程池入門 Callable 和 Future
  • Java 多線程(四)ThreadPoolExecutor 線程池各參數的意義
  • Java 多線程(五)Lock 和 Condition 實作線程同步通信
  • Java 多線程(六)Semaphore 實作信号燈
  • Java 多線程(七)CyclicBarrier 同步的工具類
  • Java 多線程(八)CountDownLatch 同步工具類
  • Java 多線程(九)Exchanger 同步工具類
  • Java 多線程(十)ArrayBlockingQueue 阻塞隊列
  • Java 多線程(十一)JDK 同步集合

線程池的概念與 Executors 類的應用

在 TCP 伺服器程式設計模型中,當一個用戶端連接配接到伺服器,伺服器要起一個線程為之服,當用戶端的回話結束時,線程也就結束了。

即每一個用戶端連接配接,伺服器就要為之建立一個新的線程。

如果通路伺服器的用戶端很多,那麼伺服器要不斷的建立和銷毀線程,這樣将嚴重影響伺服器的性能。

我們可以建立一些線程,他們的集合稱為線程池,當伺服器接收到一個客戶請求後,就從線程池中取出一個空閑的線程為之服務,服務完成後不關閉該線程,而是将該線程還回到線程池中.

線上程池的程式設計模式下,任務是交給整個線程池,而不是直接交給某個線程。

線程池拿到任務後,就在内部找有空閑的線程,再把任務交給内部某個空閑的線程,任務是交給整個線程池,但可以同時向一個線程池中送出多個任務.

一些常用線程池 API:

建立固定大小的線程池:

ExecutorService threadPool = Executors.newFixedThreadPool(3);
threadPool.execute(Runnable runnable);

建立緩存的線程池(如果線程不夠自動建立新的線程滿足服務)

ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.execute(Runnable runnable);

建立單一線程池(線程裡面隻有一個線程,如果該線程意外死亡,那麼系統會自動建立一個新的線程來代替)

ExecutorService threadPool = Executors.newSingleThreadExecutor();
threadPool.execute(Runnable runnable);

//執行完任務後關閉線程池,
threadPool.shutdown();

//不管任務是否完成都關閉線程池
threadPool.shutdownNow();

用線程池啟動定時器.
Executors.newScheduledThreadPool(3).schedule(new Runnable(){
    @Override
    publicvoid run() {
    }
}, 20, TimeUnit.SECONDS);
           

Callable 和 Future 的用法

通過這兩個類可以得到線程執行後傳回的結果。

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        //通過submit方法送出任務
        Future<String> future = executorService.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "hello world";
            }
        });

        System.out.println("等待傳回的結果");
        try {
            System.out.println("傳回的結果,"+future.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
           

Future 取得的結果類型和 Callable 傳回的結果類型必須一緻,這是通過泛型來實作的.

submit() 方法傳回的 Future 對象可以取消任務.

CompletionService 用于送出一組 Callable 任務,其中 take() 方法傳回已完成的一個 Callable 任務對應的 Future 對象

        ExecutorService executorService2 = Executors.newFixedThreadPool(3);
        CompletionService<Integer> service = new ExecutorCompletionService<Integer>(
                executorService2);
        for (int i = 0; i < 10; i++) {
            final int k = i;
                service.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    Thread.sleep(new Random().nextInt(5000));
                    return k;
                }
            });
        }

        try {
            for(int i = 0; i < 10; i++){
                System.out.println(service.take().get());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }