Executors創建線程池有哪幾種方式?


Executors如何創建線程池?

Executors 類是從 JDK 1.5 開始就新增的線程池創建的靜態工廠類,它就是創建線程池的,但是很多的大廠已經不建議使用該類去創建線程池。原因在於,該類創建的很多線程池的內部使用了無界任務隊列,在並發量很大的情況下會導致 JVM 拋出 OutOfMemoryError,直接讓 JVM 崩潰,影響嚴重。

 

但是 Executors 類究竟是如何使用的?

1. newFixedThreadPool,創建定長線程池,每當提交一個任務就創建一個線程,直到達到線程池的最大數量,這時線程數量不再變化,當線程發生錯誤結束時,線程池會補充一個新的線程。

package constxiong.concurrency.a011;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 測試創建定長線程池
 * @author ConstXiong
 */
public class TestNewFixedThreadPool {

	public static void main(String[] args) {
		//創建工作線程數為 3 的線程池,每當提交一個任務就創建一個線程,直到達到線程池的最大數量,這時線程數量不再變化,當線程發生錯誤結束時,線程池會補充一個新的線程
		ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
		//提交 6 個任務
		for (int i = 0; i <6; i++) {
			final int index = i;
			fixedThreadPool.execute(() -> {
				try {
					//休眠 3 秒
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " index:" + index);
			});
		}
		
		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("4秒后...");
		
		//關閉線程池后,已提交的任務仍然會執行完
		fixedThreadPool.shutdown();
	}
	
}

打印結果:

pool-1-thread-2 index:1
pool-1-thread-3 index:2
pool-1-thread-1 index:0
4秒后...
pool-1-thread-1 index:4
pool-1-thread-3 index:5
pool-1-thread-2 index:3

 

2. newCachedThreadPool,創建可緩存的線程池,如果線程池的容量超過了任務數,自動回收空閑線程,任務增加時可以自動添加新線程,線程池的容量不限制。

package constxiong.concurrency.a011;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 測試創建可緩存的線程池
 * @author ConstXiong
 */
public class TestNewCachedThreadPool {
	
	public static void main(String[] args) {
		//創建可緩存的線程池,如果線程池的容量超過了任務數,自動回收空閑線程,任務增加時可以自動添加新線程,線程池的容量不限制
		ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

		for (int i = 0; i <6; i++) {
			final int index = i;
			cachedThreadPool.execute(() -> {
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " index:" + index);
			});
		}
		
		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("4秒后...");
		
		cachedThreadPool.shutdown();
		
	}
	
}

打印結果可以看出,創建的線程數與任務數相等

pool-1-thread-1 index:0
pool-1-thread-3 index:2
pool-1-thread-6 index:5
pool-1-thread-4 index:3
pool-1-thread-5 index:4
pool-1-thread-2 index:1
4秒后...

 

3. newScheduledThreadPool,創建定長線程池,可執行周期性的任務。

package constxiong.concurrency.a011;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 測試創建定長線程池,可執行周期性的任務
 * @author ConstXiong
 */
public class TestNewScheduledThreadPool {

	public static void main(String[] args) {
		//創建定長線程池,可執行周期性的任務
		ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
		
		for (int i = 0; i <3; i++) {
			final int index = i;
			//scheduleWithFixedDelay 固定的延遲時間執行任務; scheduleAtFixedRate 固定的頻率執行任務
			scheduledThreadPool.scheduleWithFixedDelay(() -> {
					System.out.println(Thread.currentThread().getName() + " index:" + index);
			}, 0, 3, TimeUnit.SECONDS);
		}
		
		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("4秒后...");
		
		scheduledThreadPool.shutdown();

	}
}

打印結果:

pool-1-thread-1 index:0
pool-1-thread-3 index:2
pool-1-thread-2 index:1
pool-1-thread-1 index:0
pool-1-thread-2 index:1
pool-1-thread-3 index:2
4秒后...

 

4. newSingleThreadExecutor,創建單線程的線程池,線程異常結束,會創建一個新的線程,能確保任務按提交順序執行。

package constxiong.concurrency.a011;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 測試單線程的線程池
 * @author ConstXiong
 */
public class TestNewSingleThreadExecutor {
	
	public static void main(String[] args) {
		//單線程的線程池,線程異常結束,會創建一個新的線程,能確保任務按提交順序執行
		ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
		
		//提交 3 個任務
		for (int i = 0; i <3; i++) {
			final int index = i;
			singleThreadPool.execute(() -> {
				
				//執行第二個任務時,報錯,測試線程池會創建新的線程執行任務三
				if (index == 1) {
					throw new RuntimeException("線程執行出現異常");
				}
				
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " index:" + index);
			});
		}
		
		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("4秒后...");
		
		singleThreadPool.shutdown();
	}

}

打印結果可以看出,即使任務出現了異常,線程池還是會自動補充一個線程繼續執行下面的任務

pool-1-thread-1 index:0
Exception in thread "pool-1-thread-1" 
java.lang.RuntimeException: 線程執行出現異常
	at constxiong.concurrency.a011.TestNewSingleThreadExecutor.lambda$0(TestNewSingleThreadExecutor.java:21)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
4秒后...
pool-1-thread-2 index:2

 

5. newSingleThreadScheduledExecutor,創建單線程可執行周期性任務的線程池。

package constxiong.concurrency.a011;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 測試單線程可執行周期性任務的線程池
 * @author ConstXiong
 */
public class TestNewSingleThreadScheduledExecutor {

	public static void main(String[] args) {
		//創建單線程可執行周期性任務的線程池
		ScheduledExecutorService singleScheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
		
		//提交 3 個固定頻率執行的任務
		for (int i = 0; i <3; i++) {
			final int index = i;
			//scheduleWithFixedDelay 固定的延遲時間執行任務; scheduleAtFixedRate 固定的頻率執行任務
			singleScheduledThreadPool.scheduleAtFixedRate(() -> {
				System.out.println(Thread.currentThread().getName() + " index:" + index);
			}, 0, 3, TimeUnit.SECONDS);
		}
		
		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("4秒后...");
		
		singleScheduledThreadPool.shutdown();
	}
	
}

打印機結果可以看出 0-2 任務都被執行了 2 個周期

pool-1-thread-1 index:0
pool-1-thread-1 index:1
pool-1-thread-1 index:2
pool-1-thread-1 index:0
pool-1-thread-1 index:1
pool-1-thread-1 index:2
4秒后...

 

6. newWorkStealingPool,創建任務可竊取線程池,空閑線程可以竊取其他任務隊列的任務,不保證執行順序,適合任務耗時差異較大。

package constxiong.concurrency.a011;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 測試可任務竊取線程池
 * @author ConstXiong
 */
public class TestNewWorkStealingPool {

	public static void main(String[] args) {
		//創建 4個工作線程的 任務可竊取線程池,如果不設置並行數,默認取 CPU 總核數
		ExecutorService workStealingThreadPool = Executors.newWorkStealingPool(4);
		
		for (int i = 0; i <10; i++) {
			final int index = i;
			workStealingThreadPool.execute(() -> {
				try {
					//模擬任務執行時間為 任務編號為0 1 2 的執行時間需要 3秒;其余任務200 毫秒,導致任務時間差異較大
					if (index <= 2) {
						Thread.sleep(3000);
					} else {
						Thread.sleep(200);
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " index:" + index);
			});
		}
		
		try {
			Thread.sleep(10000);//休眠 10 秒
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("10秒后...");
	}
	
}

打印結果可以看出,線程 ForkJoinPool-1-worker-0 把3-9的任務都執行完

ForkJoinPool-1-worker-0 index:3
ForkJoinPool-1-worker-0 index:4
ForkJoinPool-1-worker-0 index:5
ForkJoinPool-1-worker-0 index:6
ForkJoinPool-1-worker-0 index:7
ForkJoinPool-1-worker-0 index:8
ForkJoinPool-1-worker-0 index:9
ForkJoinPool-1-worker-1 index:0
ForkJoinPool-1-worker-3 index:2
ForkJoinPool-1-worker-2 index:1
10秒后...


 


 

所有資源資源匯總於公眾號



 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM