1、Executor
執行緒池頂級介面。定義方法,void execute(Runnable)。方法是用於處理任務的一個服務 方法。呼叫者提供 Runnable 介面的實現,執行緒池通過執行緒執行這個 Runnable。服務方法無 返回值的。是 Runnable 介面中的 run 方法無返回值。 常用方法 - void execute(Runnable) 作用是: 啟動執行緒任務的。
2、ExecutorService
Executor 介面的子介面。提供了一個新的服務方法,submit。有返回值(Future 型別)。 submit 方法提供了 overload 方法。其中有引數型別為 Runnable 的,不需要提供返回值的; 有引數型別為 Callable,可以提供執行緒執行後的返回值。 Future,是 submit 方法的返回值。代表未來,也就是執行緒執行結束後的一種結果。如返 回值。 常見方法 - void execute(Runnable), Future submit(Callable), Future submit(Runnable) 執行緒池狀態: Running, ShuttingDown, Termitnaed Running - 執行緒池正在執行中。活動狀態。 ShuttingDown - 執行緒池正在關閉過程中。優雅關閉。一旦進入這個狀態,執行緒池不再接 收新的任務,處理所有已接收的任務,處理完畢後,關閉執行緒池。 Terminated - 執行緒池已經關閉。
3、Callable
可執行介面。 類似 Runnable 介面。也是可以啟動一個執行緒的介面。其中定義的方法是 call。call 方法的作用和 Runnable 中的 run 方法完全一致。call 方法有返回值。 介面方法 : Object call();相當於 Runnable 介面中的 run 方法。區別為此方法有返回值。 不能丟擲已檢查異常。 和 Runnable 介面的選擇 - 需要返回值或需要丟擲異常時,使用 Callable,其他情況可 任意選擇。
4、Executors
工具型別。為 Executor 執行緒池提供工具方法。可以快速的提供若干種執行緒池。如:固定 容量的,無限容量的,容量為 1 等各種執行緒池。 執行緒池是一個程式級的重量級資源。預設的生命週期和 JVM 一致。當開啟執行緒池後, 直到 JVM 關閉為止,是執行緒池的預設生命週期。如果手工呼叫 shutdown 方法,那麼執行緒池 執行所有的任務後,自動關閉。 開始 - 建立執行緒池。 結束 - JVM 關閉或呼叫 shutdown 並處理完所有的任務。 類似 Arrays,Collections 等工具型別的功用。
5、newFixedThreadPool
固定容量的執行緒池
容量固定的執行緒池。活動狀態和執行緒池容量是有上限的執行緒池。所有的執行緒池中,都有 一個任務佇列。使用的是 BlockingQueue作為任務的載體。當任務數量大於執行緒 池容量的時候,沒有執行的任務儲存在任務佇列中,當執行緒有空閒的,自動從佇列中取出任 務執行。 使用場景: 大多數情況下,使用的執行緒池,首選推薦 FixedThreadPool。OS 系統和硬體 是有執行緒支援上限。不能隨意的無限制提供執行緒池。 執行緒池預設的容量上限是 Integer.MAX_VALUE。 常見的執行緒池容量: PC - 200。 伺服器 - 1000~10000 queued tasks - 任務佇列 completed tasks - 結束任務佇列
/**
* 執行緒池
* 固定容量執行緒池
* FixedThreadPool - 固定容量執行緒池。建立執行緒池的時候,容量固定。
* 構造的時候,提供執行緒池最大容量
* new xxxxx ->
* ExecutorService - 執行緒池服務型別。所有的執行緒池型別都實現這個介面。
* 實現這個介面,代表可以提供執行緒池能力。
* shutdown - 優雅關閉。 不是強行關閉執行緒池,回收執行緒池中的資源。而是不再處理新的任務,將已接收的任務處理完畢後
* 再關閉。
* Executors - Executor的工具類。類似Collection和Collections的關係。
* 可以更簡單的建立若干種執行緒池。
*/
package concurrent.t08;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Test_02_FixedThreadPool {
public static void main(String[] args) {
ExecutorService service =
Executors.newFixedThreadPool(5);
for(int i = 0; i < 6; i++){
service.execute(new Runnable() {
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " - test executor");
}
});
}
System.out.println(service);
service.shutdown();
// 是否已經結束, 相當於回收了資源。
System.out.println(service.isTerminated());
// 是否已經關閉, 是否呼叫過shutdown方法
System.out.println(service.isShutdown());
System.out.println(service);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
// service.shutdown();
System.out.println(service.isTerminated());
System.out.println(service.isShutdown());
System.out.println(service);
}
}
複製程式碼
結果:
java.util.concurrent.ThreadPoolExecutor@42a57993[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
false
true
java.util.concurrent.ThreadPoolExecutor@42a57993[Shutting down, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
pool-1-thread-2 - test executor
pool-1-thread-1 - test executor
pool-1-thread-5 - test executor
pool-1-thread-4 - test executor
pool-1-thread-3 - test executor
pool-1-thread-2 - test executor
true
true
java.util.concurrent.ThreadPoolExecutor@42a57993[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]
複製程式碼
6、future
未來結果,代表執行緒任務執行結束後的結果。獲取執行緒執行結果的方式是通過 get 方法 獲取的。get 無參,阻塞等待執行緒執行結束,並得到結果。get 有參,阻塞固定時長,等待 執行緒執行結束後的結果,如果在阻塞時長範圍內,執行緒未執行結束,丟擲異常。 常用方法: T get() T get(long, TimeUnit)
/**
* 執行緒池
* 固定容量執行緒池
*/
package concurrent.t08;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
public class Test_03_Future {
public static void main(String[] args) throws InterruptedException, ExecutionException {
/*FutureTask<String> task = new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
return "first future task";
}
});
new Thread(task).start();
System.out.println(task.get());*/
ExecutorService service = Executors.newFixedThreadPool(1);
Future<String> future = service.submit(new Callable<String>() {
@Override
public String call() {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("aaa");
return Thread.currentThread().getName() + " - test executor";
}
});
System.out.println(future);
System.out.println(future.isDone()); // 檢視執行緒是否結束, 任務是否完成。 call方法是否執行結束
System.out.println(future.get()); // 獲取call方法的返回值。
System.out.println(future.isDone());
}
}
複製程式碼
結果:
java.util.concurrent.FutureTask@6d6f6e28
false
aaa
pool-1-thread-1 - test executor
true
複製程式碼
7、CachedThreadPool
快取的執行緒池。容量不限(Integer.MAX_VALUE)。自動擴容。容量管理策略:如果執行緒 池中的執行緒數量不滿足任務執行,建立新的執行緒。每次有新任務無法即時處理的時候,都會 建立新的執行緒。當執行緒池中的執行緒空閒時長達到一定的臨界值(預設 60 秒),自動釋放執行緒。 預設執行緒空閒 60 秒,自動銷燬。 應用場景: 內部應用或測試應用。 內部應用,有條件的內部資料瞬間處理時應用,如: 電信平臺夜間執行資料整理(有把握在短時間內處理完所有工作,且對硬體和軟體有足夠的 信心)。 測試應用,在測試的時候,嘗試得到硬體或軟體的最高負載量,用於提供 FixedThreadPool 容量的指導。
/**
* 執行緒池
* 無容量限制的執行緒池(最大容量預設為Integer.MAX_VALUE)
*/
package concurrent.t08;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Test_05_CachedThreadPool {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
System.out.println(service);
for(int i = 0; i < 5; i++){
service.execute(new Runnable() {
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " - test executor");
}
});
}
System.out.println(service);
try {
TimeUnit.SECONDS.sleep(65);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(service);
}
}
複製程式碼
結果:
java.util.concurrent.ThreadPoolExecutor@7f31245a[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@7f31245a[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
pool-1-thread-5 - test executor
pool-1-thread-2 - test executor
pool-1-thread-4 - test executor
pool-1-thread-1 - test executor
pool-1-thread-3 - test executor
java.util.concurrent.ThreadPoolExecutor@7f31245a[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 5]
Process finished with exit code 0
複製程式碼
8、ScheduledThreadPool
計劃任務執行緒池。可以根據計劃自動執行任務的執行緒池。 scheduleAtFixedRate(Runnable, start_limit, limit, timeunit) runnable - 要執行的任務。 start_limit - 第一次任務執行的間隔。 limit - 多次任務執行的間隔。 timeunit - 多次任務執行間隔的時間單位。 使用場景: 計劃任務時選用(DelaydQueue),如:電信行業中的資料整理,沒分鐘整 理,沒小時整理,每天整理等。
/**
* 執行緒池
* 計劃任務執行緒池。
*/
package concurrent.t08;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test_07_ScheduledThreadPool {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
System.out.println(service);
// 定時完成任務。 scheduleAtFixedRate(Runnable, start_limit, limit, timeunit)
// runnable - 要執行的任務。
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}, 0, 300, TimeUnit.MILLISECONDS);
}
}
複製程式碼
結果:
java.util.concurrent.ScheduledThreadPoolExecutor@14ae5a5[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
pool-1-thread-1
pool-1-thread-1
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
複製程式碼
9、SingleThreadExceutor
單一容量的執行緒池。
使用場景: 保證任務順序時使用。如: 遊戲大廳中的公共頻道聊天。秒殺。
/**
* 執行緒池
* 容量為1的執行緒池。 順序執行。
*/
package concurrent.t08;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Test_06_SingleThreadExecutor {
public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
System.out.println(service);
for(int i = 0; i < 5; i++){
service.execute(new Runnable() {
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " - test executor");
}
});
}
}
}
複製程式碼
結果:
java.util.concurrent.Executors$FinalizableDelegatedExecutorService@14ae5a5
pool-1-thread-1 - test executor
pool-1-thread-1 - test executor
pool-1-thread-1 - test executor
pool-1-thread-1 - test executor
pool-1-thread-1 - test executor
複製程式碼
10、ForkJoinPool
分支合併執行緒池(mapduce 類似的設計思想)。適合用於處理複雜任務。 初始化執行緒容量與 CPU 核心數相關。 執行緒池中執行的內容必須是 ForkJoinTask 的子型別(RecursiveTask,RecursiveAction)。
ForkJoinPool - 分支合併執行緒池。 可以遞迴完成複雜任務。要求可分支合併的任務必須是 ForkJoinTask 型別的子型別。其中提供了分支和合並的能力。ForkJoinTask 型別提供了兩個抽象子型別,RecursiveTask 有返回結果的分支合併任務,RecursiveAction 無返回結果的分支合併任務。(Callable/Runnable)compute 方法:就是任務的執行邏輯。
ForkJoinPool 沒有所謂的容量。預設都是 1 個執行緒。根據任務自動的分支新的子執行緒。當子執行緒任務結束後,自動合併。所謂自動是根據 fork 和 join 兩個方法實現的。應用: 主要是做科學計算或天文計算的。資料分析的
/**
* 執行緒池
* 分支合併執行緒池。
*/
package concurrent.t08;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
public class Test_08_ForkJoinPool {
final static int[] numbers = new int[1000000];
final static int MAX_SIZE = 50000;
final static Random r = new Random();
static{
for(int i = 0; i < numbers.length; i++){
numbers[i] = r.nextInt(1000);
}
}
static class AddTask extends RecursiveTask<Long>{ // RecursiveAction
int begin, end;
public AddTask(int begin, int end){
this.begin = begin;
this.end = end;
}
//
protected Long compute(){
if((end - begin) < MAX_SIZE){
long sum = 0L;
for(int i = begin; i < end; i++){
sum += numbers[i];
}
// System.out.println("form " + begin + " to " + end + " sum is : " + sum);
return sum;
}else{
int middle = begin + (end - begin)/2;
AddTask task1 = new AddTask(begin, middle);
AddTask task2 = new AddTask(middle, end);
task1.fork();// 就是用於開啟新的任務的。 就是分支工作的。 就是開啟一個新的執行緒任務。
task2.fork();
// join - 合併。將任務的結果獲取。 這是一個阻塞方法。一定會得到結果資料。
return task1.join() + task2.join();
}
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException, IOException {
long result = 0L;
for(int i = 0; i < numbers.length; i++){
result += numbers[i];
}
System.out.println(result);
ForkJoinPool pool = new ForkJoinPool();
AddTask task = new AddTask(0, numbers.length);
Future<Long> future = pool.submit(task);
System.out.println(future.get());
}
}
複製程式碼
結果:
499664397
499664397
複製程式碼