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();