1. 程式人生 > >java執行緒池介紹(一)

java執行緒池介紹(一)

今天看了一下java併發包中的API,這裡做一個總結。
首先我們先看一下,java執行緒池相關的類以及他們的關係uml圖
這裡寫圖片描述
從類圖和原始碼中可以瞭解到,Executors類是提供執行緒池建立的類,而實現Executo介面系列的類則是提供執行緒池所有用的行為。例如execute、submit、shutDown等
Executors類中提供四種建立執行緒池的靜態方法。

建立執行緒池的幾種方式

建立快取執行緒池

  • 建立可快取的執行緒池,如果沒有可用的執行緒,會建立一個新的,並銷燬超過60s沒有重用的執行緒
public static void newCachedThreadPool
(){ MyRunnable myRunnable = new MyRunnable(); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { executorService.execute(myRunnable); } executorService.shutdown(); }

建立固定數量的執行緒池

  • 建立固定執行緒數的執行緒池
 public static void newFixedThreadPool(){
        MyRunnable myRunnable = new MyRunnable();
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            executorService.execute(myRunnable);
        }
        executorService.shutdown();
    }

建立單一執行緒的執行緒池

  • 建立一個單執行緒化的Executor。
public static void newSingleThreadExecutor(){
        MyRunnable myRunnable = new MyRunnable();
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            executorService.execute(myRunnable);
        }
        executorService.shutdown();
    }

建立具有周期性的執行緒池

    public static void newSchduleThreadExecutor(){
        MyRunnable myRunnable = new MyRunnable();
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 5; i++) {
            executorService.execute(myRunnable);
        }
        executorService.shutdown();
    }

對原始碼進行的一番分析

通過檢視Executors的原始碼可以瞭解到其中newCachedThreadPool()和newFixedThreadPool(int nThreads)建立多執行緒的方法其實是交給ThreadPoolExecutor來執行的。

 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

ThreadPoolExecutor的構造方法有以下引數說明:
corePoolSize 核心執行緒數
maximumPoolSize 允許的最大執行緒數
keepAliveTime 單個執行緒存或時間
TimeUnit 持續時間的單位
BlockingQueue 任務執行前保持任務的佇列

我們可以根據ThreadPoolExecutor提供的構造方法來自定義執行緒池

 //建立等待佇列
        BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(10);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, blockingQueue);

        for (int i = 0; i <10 ; i++) {
            threadPoolExecutor.submit(new MyCallable<String>());
        }
        threadPoolExecutor.shutdown();

ExecutorService的行為方法

通過Executors建立方式可以檢視到,newCachedThreadPool和newFixedThreadPool執行緒池的建立返回物件是ExecutorService,這是一個提供執行緒池操作的介面。
它的execute()和submit方法值得我們瞭解一下
從執行緒池的繼承結構來看,它們都繼承Executor介面,該介面只提供一個方法

void execute(Runnable command);

因此所有建立的執行緒池都會有execute的方法實現,ExecutorService還提供了不同的submit方法和終止執行緒的shutdown方法

//帶Future返回值的submit方法。
 <T> Future<T> submit(Callable<T> task);
 <T> Future<T> submit(Runnable task, T result);
     Future<?> submit(Runnable task);
     //結束多執行緒的執行
     void shutdown();

我們看到ExecutorService提供的submit中傳入的引數有兩類,一類是Runnable,另一類是Callable。Runnable大家都很熟悉了,是建立多執行緒提供的介面方法。我們可以通過實現Runnable介面來實現一個多執行緒要執行的run方法。但是這個run方法沒有返回值,而Calleable介面與Runnable類似,唯一不同的就是它有返回值

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Callable介面

從這裡我們就看出ExecutorService的submit的區別了,
一個傳入Callable引數的submit方法可以有返回值,
傳入Runnable引數的submit方法沒有返回值。
我們可以通過例子看下Callable的用法

public static void callableSubmitTest() throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        List<Future<String>> list = new ArrayList<Future<String>>();
        for (int i = 0; i <10 ; i++) {
            Future<String> future = executorService.submit(new MyCallable<String>());
            list.add(future);
        }
        for (int i = 0; i < list.size(); i++){
            Future<String> future = list.get(i);
            System.out.println("future.get() = " + future.get() + " is canceled :" + future.isDone());
        }
        executorService.shutdown();
    }
    static class MyCallable<String> implements Callable<String>{
        public String call() throws Exception {
            System.out.println(Thread.currentThread().getName() + " 執行緒名...");
            return (String) Thread.currentThread().getName();
        }
    }

Future

ExecutorService的submit都返回了Future物件,而這個物件是做什麼用的呢?
Future也是一個介面類,這裡面定義了多執行緒任務的完成狀態。
例如isCanceled()、isDone()等等這些方法,用於判斷多執行緒任務的執行狀態。
通過Future的get()方法獲取Callable返回的結果。

//在任務完成之前結束,返回true
boolean isCancelled();
//在任務完成後,返回true
boolean isDone();
//獲取結果值
V get();