今天看了一下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類似,唯一不同的就是它有傳回值
@FunctionalInterfacepublic interface Callable<V> { V call() throws Exception;}@FunctionalInterfacepublic 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返回的結果。
//在任務完成之前結束,返回trueboolean isCancelled();//在任務完成後,返回trueboolean isDone();//擷取結果值V get();
還有一個ScheduleExecutorService的方法沒有進行介紹,下一次再與大家分享。
參考部落格:
http://wiki.jikexueyuan.com/project/java-concurrency/executor.html
代碼例子:
https://github.com/hpulzl/lzl_workspace/tree/master/thread_demo