天天看點

多線程 - 線程池的實作概述API代碼示例

概述

系統啟動一個新線程的成本是比較高的,因為它需要與系統互動,使用線程池可以有效地控制系統中并發線程的數量。尤其是當系統中需要建立大量生命周期很短的線程時,這種效果尤為明顯。 線程池會在程式啟動時建立一定數量的線程。當程式将一個Runnable對象或Callable對象傳給線程池,線程池會啟動一個線程來執行它的run()方法或call()方法。當run()方法或call()方法執行結束後,該線程不會立刻死亡,而是再次傳回線程池中成為空閑狀态,等待執行下一個任務。

API

從Java 5以後,JDK新增了一個Executors工廠類來建立線程池,該工廠類包含如下幾個靜态方法:

  • newCachedThreadPool():建立一個具有緩沖功能的線程池,系統根據需要建立線程,這些線程将會被緩存線上程池中。
  • newFixedThreadPool(int nThreads):建立一個可重用、具有固定線程數的線程池。
  • newSingleThreadExecutor():建立一個隻有一個線程的線程池。
  • newScheduledThreadPool(int corePoolSize):建立具有指定線程數的線程池,它可以在指定延遲後執行任務。corePoolSize指線程池中所儲存的線程數,即使線程是空閑的也被儲存線上程池内。
  • newSingleThreadScheduledExecutor():建立隻有一個線程的線程池,它可以在指定延遲後執行任務。

前3個方法傳回一個ExecutorService對象,它代表線程池,可以執行Runnable或Callable任務。後2個方法傳回一個ScheduledExecutorService對象,它是ExecutorService的子類,在指定延遲後執行線程任務。ExecutorService提供了3個方法來執行線程任務:

  • Future<?> submit(Runnable task):将一個Runnable任務送出給線程池,線程池将在有空閑線程是執行Runnable任務。Future對象代表Runnable任務的傳回值——run()方法沒有傳回值,将傳回null。
  • <T> Future<T> submit(Runnable task, T result):将一個Runnable任務送出給線程池,線程池将在有空閑線程是執行Runnable任務。其中result表示傳回值,線程執行結束後傳回result。
  • <T> Future<T> submit(Callable<T> task):将一個Callable任務送出給線程池,線程池将在有空閑線程是執行Callable任務。Future對象代表Callable任務的傳回值。

當執行完線程任務後,應該關閉線程池。調用shutdown()方法後,線程池将不再接收新的線程任務,并将所有正在執行的線程任務執行完畢後關閉線程池。shutdownNow()方法會停止所有正在執行的線程任務并關閉線程池。

代碼示例

使用線程池來執行線程任務的步驟如下: (1)調用Executors類的靜态工廠方法建立一個ExecutorService對象,該對象代表一個線程池; (2)建立Runnable實作類或Callable實作類的執行個體,作為線程任務; (3)調用ExecutorService對象的submit()方法來送出線程任務; (4)線程任務執行完畢後,關閉線程池。

package Demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class MyTask implements Runnable {
    @Override
    public void run() {
	for (int i = 0; i < 100; i++) {
	    System.out.println(Thread.currentThread().getName() + "的i值為" + i);
	}
    }
}

public class ThreadPoolDemo {

    public static void main(String[] args) {
	// 建立線程池,容量為4
	ExecutorService threadPool = Executors.newFixedThreadPool(4);
	// 送出三個線程任務
	threadPool.submit(new MyTask());
	threadPool.submit(new MyTask());
	threadPool.submit(new MyTask());
	// 關閉線程池
	threadPool.shutdown();
    }
}
           

測試結果:

pool-1-thread-1的i值為0
pool-1-thread-2的i值為0
pool-1-thread-2的i值為1
pool-1-thread-2的i值為2
pool-1-thread-3的i值為0
pool-1-thread-2的i值為3
pool-1-thread-1的i值為1
pool-1-thread-2的i值為4
pool-1-thread-2的i值為5
pool-1-thread-2的i值為6
pool-1-thread-3的i值為1
pool-1-thread-2的i值為7
pool-1-thread-2的i值為8
pool-1-thread-2的i值為9
pool-1-thread-2的i值為10
pool-1-thread-2的i值為11
pool-1-thread-2的i值為12
pool-1-thread-2的i值為13
......