歡迎大家訪問我的個人博客:L_SKH’Blog
一、FixedThreadPool
固定數量線程池
package org.skh.c026;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @Created IntelliJ IDEA.
* @Author L_SKH
* @Date 2019/11/18 15:08
*/
public class T05_ThreadPool {
public static void main(String[] args) throws InterruptedException {
//固定數量的線程池
ExecutorService service = Executors.newFixedThreadPool(5);
//向五個線程提交6個任務
//因爲是固定數量 所以不會有第六個線程 也所以某個線程會執行兩個任務
for (int i=0;i<6;i++){
service.execute(()->{
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
});
}
System.out.println(service); //打印線程池信息
/**
* 狀態: Running,
* 線程池大小: pool size = 5,
* 存活的線程數: active threads = 5,
* 等待的任務的數量: queued tasks = 1,
* 完成的任務數量: completed tasks = 0
*/
service.shutdown(); //關閉線程池 但不會立即關閉只會返回一個true 要等待所有任務完成
System.out.println(service.isTerminated()); //是否停止
System.out.println(service.isShutdown()); //是否關閉 返回true但沒有真的關閉 只是一個flag
System.out.println(service);
TimeUnit.SECONDS.sleep(5);
System.out.println(service.isTerminated());
System.out.println(service.isShutdown()); //此時纔是真的關閉了 因爲任務已全部完成
System.out.println(service);
}
}
二、CachedPool
與之前的線程池不同 這個是隻有提交了任務時纔會啓動一個線程 一開始是沒有線程的 來一個任務就開啓一個線程 當然前提是線程池裏沒有空閒的並且存活的線程 另外如果一個線程如果在60s內沒有被使用 則會被kill
package org.skh.c026;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @Created IntelliJ IDEA.
* @Author L_SKH
* @Date 2019/11/18 20:59
*/
public class T08_CachedPool {
public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newCachedThreadPool();
System.out.println(service);
for (int i=0;i<2;i++){
service.execute(()->{
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
});
}
System.out.println(service);
TimeUnit.SECONDS.sleep(80);
System.out.println(service);
}
}
三、SingleThreadPool
顧名思義,只有一個線程處理任務的線程,線程池中只有一個線程 所以下面程序中的五個任務只有一個線程執行。所以可以保證任務執行的順序性
package org.skh.c026;
/**
* @Created IntelliJ IDEA.
* @Author L_SKH
* @Date 2019/11/18 21:22
*/
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class T09_SingleThreadPool {
public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
int j = i;
service.execute(() -> {
System.out.println(j + " " + Thread.currentThread().getName());
});
}
}
}
四、ScheduledPool
ScheduledPool Scheduled: 計劃中的,定時的。執行定時的任務,類似Delay, 可以替代Timer。
package org.skh.c026;
/**
* @Created IntelliJ IDEA.
* @Author L_SKH
* @Date 2019/11/18 21:27
*/
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class T10_ScheduledPool {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
// 使用固定的頻率執行某個任務
// 四個參數
// command: 執行的任務
// initialDelay: 第一次執行延時多久執行
// period: 每隔多久執行一次這個任務
// unit: 時間單位
service.scheduleAtFixedRate(() -> {
try {
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}, 0, 500, TimeUnit.MILLISECONDS); // 每隔500ms打印一下線程名稱
//每經過500ms 會在執行一次任務 最大線程數量爲4個 如果sleep的時間大於500會啓用另一個線程來執行
//當所有的四個線程都在執行任務時 會等待某個線程空閒下來來執行它
}
}
五、WorkStealingPool
顧名思義,每個線程都有自己維護的隊列,當一個線程處理完自己的隊列後,會去‘偷’別人的任務隊列進行處理。
package org.skh.c026;
/**
* @Created IntelliJ IDEA.
* @Author L_SKH
* @Date 2019/11/18 21:42
*/
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class T11_WorkStealingPool {
public static void main(String[] args) throws IOException {
// CPU 核數
System.out.println(Runtime.getRuntime().availableProcessors());
// workStealingPool 會自動啓動cpu核數個線程去執行任務
ExecutorService service = Executors.newWorkStealingPool();
service.execute(new R(1000)); // 我的cpu核數爲12 啓動13個線程,其中第一個是1s執行完畢,其餘都是2s執行完畢,
// 有一個任務會進行等待,當第一個執行完畢後,會再次偷取第十三個任務執行
for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) {
service.execute(new R(2000));
}
// 因爲work stealing 是deamon線程,即後臺線程,精靈線程,守護線程
// 所以當main方法結束時, 此方法雖然還在後臺運行,但是無輸出
// 可以通過對主線程阻塞解決
System.in.read();
}
static class R implements Runnable {
int time;
R(int time) {
this.time = time;
}
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + time);
}
}
}
六、ForkJoinPool
將一個任務拆分多個任務執行(可以無限切分),然後將結果合併
package org.skh.c026;
/**
* @Created IntelliJ IDEA.
* @Author L_SKH
* @Date 2019/11/18 21:54
*/
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.RecursiveTask;
/**
* T12_ForkJoinPool 分而治之
* Fork: 分叉
* Join: 合併
* <p>
* 將一個任務拆分多個任務執行(可以無限切分),然後將結果合併
* <p>
* 比如大量的並行計算, 如下: 求100_0000個數字之和, 使用多線程
*/
public class T12_ForkJoinPool {
static int[] nums = new int[100_0000];
static final int MAX_NUM = 5_0000; // 每個線程最多可以運行5萬個數字相加
static Random random = new Random();
// 初始化這100_000個數字, 每個數字範圍在100之內
static {
for (int i = 0; i < nums.length; i++) {
nums[i] = random.nextInt(100);
}
// 所有數字和, 事先計算:
System.out.println(Arrays.stream(nums).sum()); // 使用單線程stream api 進行求和
}
/**
* RecursiveAction(AddTask): 遞歸操作 沒有返回值
* RecursiveTask(AddTask2): 遞歸操作,有返回值
*/
static class AddTask extends RecursiveAction {
int start, end;
AddTask(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected void compute() {
// 進行計算
// 如果計算的數的和的範圍 小於 MAX_NUM, 進行計算,否則進行 fork
if (end - start <= MAX_NUM) {
long sum = 0;
for (int i = start; i < end; i++) {
sum += nums[i];
}
System.out.println("sum = " + sum);
} else {
int middle = (end - start) / 2;
AddTask subTask1 = new AddTask(start, middle);
AddTask subTask2 = new AddTask(middle, end);
subTask1.fork();
subTask2.fork();
}
}
}
static class AddTask2 extends RecursiveTask<Long> {
int start, end;
AddTask2(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
// 進行計算
// 如果計算的數的和的範圍 小於 MAX_NUM, 進行計算,否則進行 fork
if (end - start <= MAX_NUM) {
long sum = 0;
for (int i = start; i < end; i++) {
sum += nums[i];
}
return sum;
} else {
int middle = start + (end - start) / 2; // 注意這裏,如果有問題,會拋出java.lang.NoClassDefFoundError: Could not initialize class java.util.concurrent.locks.AbstractQueuedSynchronizer$Node 異常
AddTask2 subTask1 = new AddTask2(start, middle);
AddTask2 subTask2 = new AddTask2(middle, end);
subTask1.fork();
subTask2.fork();
//有返回值
return subTask1.join() + subTask2.join();
}
}
}
// 運行
public static void main(String[] args) throws IOException {
ForkJoinPool fjp = new ForkJoinPool();
AddTask2 task = new AddTask2(0, nums.length);
fjp.execute(task);
System.out.println(task.join());
System.in.read();
}
}