關於java線程池

首先放上一個類圖(jdk8)

在這裏插入圖片描述

下邊是根據上邊的基礎拓展出來的幾個對象,可以用executors直接生成,因爲如果用threadpoolexecutor,那麼有7個參數可以進行初始化:
int corePoolSize,(核心線程數量)
int maximumPoolSize,(最大線程數量),如果核心線程數量滿了,並且任務隊列排滿了,那麼就會新建線程直到最大線程數量
long keepAliveTime,(超過核心線程數量的線程存活時間)
TimeUnit unit,(超過核心線程數量的線程存活時間單位)
BlockingQueue workQueue,(任務隊列)
ThreadFactory threadFactory,(線程工廠)
RejectedExecutionHandler handler(拒絕策略),如果隊列滿了,並且已經到達了最大線程數量,那麼再加入任務就會執行拒絕策略

Executors類

在上邊的基礎上,我們可以從Executors中得到幾個線程池類型,這樣只需要填寫關鍵參數就行了
提供的有
Executors.new
newFixedThreadPool:固定線程數量的線程池
newSingleThreadExecutor:只有單一線程的線程池
newCachedThreadPool:緩存線程池
newScheduledThreadPool:定時任務線程池

加深練習

下邊是聽課時一個老師寫的一個練習類,可以供大家參考加深學習

/** 線程池的使用 */
public class ThreadPool {

	/**
	 * 測試: 提交15個執行時間需要3秒的任務,看線程池的狀況
	 * 
	 * @param threadPoolExecutor 傳入不同的線程池,看不同的結果
	 * @throws Exception
	 */
	public void testCommon(ThreadPoolExecutor threadPoolExecutor) throws Exception {
		// 測試: 提交15個執行時間需要3秒的任務,看超過大小的2個,對應的處理情況
		for (int i = 0; i < 15; i++) {
			int n = i;
			threadPoolExecutor.submit(new Runnable() {
				@Override
				public void run() {
					try {
						System.out.println("開始執行:" + n);
						Thread.sleep(3000L);
						System.err.println("執行結束:" + n);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
			System.out.println("任務提交成功 :" + i);
		}
		// 查看線程數量,查看隊列等待數量
		Thread.sleep(500L);
		System.out.println("當前線程池線程數量爲:" + threadPoolExecutor.getPoolSize());
		System.out.println("當前線程池等待的數量爲:" + threadPoolExecutor.getQueue().size());
		// 等待15秒,查看線程數量和隊列數量(理論上,會被超出核心線程數量的線程自動銷燬)
		Thread.sleep(15000L);
		System.out.println("當前線程池線程數量爲:" + threadPoolExecutor.getPoolSize());
		System.out.println("當前線程池等待的數量爲:" + threadPoolExecutor.getQueue().size());
	}

	/**
	 * 1、線程池信息: 核心線程數量5,最大數量10,無界隊列,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略的
	 * 
	 * @throws Exception
	 */
	private void threadPoolExecutorTest1() throws Exception {
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
				new LinkedBlockingQueue<Runnable>());
		testCommon(threadPoolExecutor);
		// 預計結果:線程池線程數量爲:5,超出數量的任務,其他的進入隊列中等待被執行
	}

	/**
	 * 2、 線程池信息: 核心線程數量5,最大數量10,隊列大小3,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略的
	 * 
	 * @throws Exception
	 */
	private void threadPoolExecutorTest2() throws Exception {
		// 創建一個 核心線程數量爲5,最大數量爲10,等待隊列最大是3 的線程池,也就是最大容納13個任務。
		// 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
				new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
					@Override
					public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
						System.err.println("有任務被拒絕執行了");
					}
				});
		testCommon(threadPoolExecutor);
		// 預計結果:
		// 1、 5個任務直接分配線程開始執行
		// 2、 3個任務進入等待隊列
		// 3、 隊列不夠用,臨時加開5個線程來執行任務(5秒沒活幹就銷燬)
		// 4、 隊列和線程池都滿了,剩下2個任務,沒資源了,被拒絕執行。
		// 5、 任務執行,5秒後,如果無任務可執行,銷燬臨時創建的5個線程
	}

	/**
	 * 3、 線程池信息: 核心線程數量5,最大數量5,無界隊列,超出核心線程數量的線程存活時間:5秒
	 * 
	 * @throws Exception
	 */
	private void threadPoolExecutorTest3() throws Exception {
		// 和Executors.newFixedThreadPool(int nThreads)一樣的
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,
				new LinkedBlockingQueue<Runnable>());
		testCommon(threadPoolExecutor);
		// 預計結:線程池線程數量爲:5,超出數量的任務,其他的進入隊列中等待被執行
	}

	/**
	 * 4、 線程池信息:
	 * 核心線程數量0,最大數量Integer.MAX_VALUE,SynchronousQueue隊列,超出核心線程數量的線程存活時間:60秒
	 * 
	 * @throws Exception
	 */
	private void threadPoolExecutorTest4() throws Exception {

		// SynchronousQueue,實際上它不是一個真正的隊列,因爲它不會爲隊列中元素維護存儲空間。與其他隊列不同的是,它維護一組線程,這些線程在等待着把元素加入或移出隊列。
		// 在使用SynchronousQueue作爲工作隊列的前提下,客戶端代碼向線程池提交任務時,
		// 而線程池中又沒有空閒的線程能夠從SynchronousQueue隊列實例中取一個任務,
		// 那麼相應的offer方法調用就會失敗(即任務沒有被存入工作隊列)。
		// 此時,ThreadPoolExecutor會新建一個新的工作者線程用於對這個入隊列失敗的任務進行處理(假設此時線程池的大小還未達到其最大線程池大小maximumPoolSize)。

		// 和Executors.newCachedThreadPool()一樣的
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
				new SynchronousQueue<Runnable>());
		testCommon(threadPoolExecutor);
		// 預計結果:
		// 1、 線程池線程數量爲:15,超出數量的任務,其他的進入隊列中等待被執行
		// 2、 所有任務執行結束,60秒後,如果無任務可執行,所有線程全部被銷燬,池的大小恢復爲0
		Thread.sleep(60000L);
		System.out.println("60秒後,再看線程池中的數量:" + threadPoolExecutor.getPoolSize());
	}

	/**
	 * 5、 定時執行線程池信息:3秒後執行,一次性任務,到點就執行 <br/>
	 * 核心線程數量5,最大數量Integer.MAX_VALUE,DelayedWorkQueue延時隊列,超出核心線程數量的線程存活時間:0秒
	 * 
	 * @throws Exception
	 */
	private void threadPoolExecutorTest5() throws Exception {
		// 和Executors.newScheduledThreadPool()一樣的
		ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
		threadPoolExecutor.schedule(new Runnable() {
			@Override
			public void run() {
				System.out.println("任務被執行,現在時間:" + System.currentTimeMillis());
			}
		}, 3000, TimeUnit.MILLISECONDS);
		System.out.println(
				"定時任務,提交成功,時間是:" + System.currentTimeMillis() + ", 當前線程池中線程數量:" + threadPoolExecutor.getPoolSize());
		// 預計結果:任務在3秒後被執行一次
	}

	/**
	 * 6、 定時執行線程池信息:線程固定數量5 ,<br/>
	 * 核心線程數量5,最大數量Integer.MAX_VALUE,DelayedWorkQueue延時隊列,超出核心線程數量的線程存活時間:0秒
	 * 
	 * @throws Exception
	 */
	private void threadPoolExecutorTest6() throws Exception {
		ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
		// 週期性執行某一個任務,線程池提供了兩種調度方式,這裏單獨演示一下。測試場景一樣。
		// 測試場景:提交的任務需要3秒才能執行完畢。看兩種不同調度方式的區別
		// 效果1: 提交後,2秒後開始第一次執行,之後每間隔1秒,固定執行一次(如果發現上次執行還未完畢,則等待完畢,完畢後立刻執行)。
		// 也就是說這個代碼中是,3秒鐘執行一次(計算方式:每次執行三秒,間隔時間1秒,執行結束後馬上開始下一次執行,無需等待)
		threadPoolExecutor.scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(3000L);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("任務-1 被執行,現在時間:" + System.currentTimeMillis());
			}
		}, 2000, 1000, TimeUnit.MILLISECONDS);

		// 效果2:提交後,2秒後開始第一次執行,之後每間隔1秒,固定執行一次(如果發現上次執行還未完畢,則等待完畢,等上一次執行完畢後再開始計時,等待1秒)。
		// 也就是說這個代碼鐘的效果看到的是:4秒執行一次。 (計算方式:每次執行3秒,間隔時間1秒,執行完以後再等待1秒,所以是 3+1)
		threadPoolExecutor.scheduleWithFixedDelay(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(3000L);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("任務-2 被執行,現在時間:" + System.currentTimeMillis());
			}
		}, 2000, 1000, TimeUnit.MILLISECONDS);
	}

	/**
	 * 7、 終止線程:線程池信息: 核心線程數量5,最大數量10,隊列大小3,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略的
	 * 
	 * @throws Exception
	 */
	private void threadPoolExecutorTest7() throws Exception {
		// 創建一個 核心線程數量爲5,最大數量爲10,等待隊列最大是3 的線程池,也就是最大容納13個任務。
		// 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
				new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
					@Override
					public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
						System.err.println("有任務被拒絕執行了");
					}
				});
		// 測試: 提交15個執行時間需要3秒的任務,看超過大小的2個,對應的處理情況
		for (int i = 0; i < 15; i++) {
			int n = i;
			threadPoolExecutor.submit(new Runnable() {
				@Override
				public void run() {
					try {
						System.out.println("開始執行:" + n);
						Thread.sleep(3000L);
						System.err.println("執行結束:" + n);
					} catch (InterruptedException e) {
						System.out.println("異常:" + e.getMessage());
					}
				}
			});
			System.out.println("任務提交成功 :" + i);
		}
		// 1秒後終止線程池
		Thread.sleep(1000L);
		threadPoolExecutor.shutdown();
		// 再次提交提示失敗
		threadPoolExecutor.submit(new Runnable() {
			@Override
			public void run() {
				System.out.println("追加一個任務");
			}
		});
		// 結果分析
		// 1、 10個任務被執行,3個任務進入隊列等待,2個任務被拒絕執行
		// 2、調用shutdown後,不接收新的任務,等待13任務執行結束
		// 3、 追加的任務在線程池關閉後,無法再提交,會被拒絕執行
	}

	/**
	 * 8、 立刻終止線程:線程池信息: 核心線程數量5,最大數量10,隊列大小3,超出核心線程數量的線程存活時間:5秒, 指定拒絕策略的
	 * 
	 * @throws Exception
	 */
	private void threadPoolExecutorTest8() throws Exception {
		// 創建一個 核心線程數量爲5,最大數量爲10,等待隊列最大是3 的線程池,也就是最大容納13個任務。
		// 默認的策略是拋出RejectedExecutionException異常,java.util.concurrent.ThreadPoolExecutor.AbortPolicy
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
				new LinkedBlockingQueue<Runnable>(3), new RejectedExecutionHandler() {
					@Override
					public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
						System.err.println("有任務被拒絕執行了");
					}
				});
		// 測試: 提交15個執行時間需要3秒的任務,看超過大小的2個,對應的處理情況
		for (int i = 0; i < 15; i++) {
			int n = i;
			threadPoolExecutor.submit(new Runnable() {
				@Override
				public void run() {
					try {
						System.out.println("開始執行:" + n);
						Thread.sleep(3000L);
						System.err.println("執行結束:" + n);
					} catch (InterruptedException e) {
						System.out.println("異常:" + e.getMessage());
					}
				}
			});
			System.out.println("任務提交成功 :" + i);
		}
		// 1秒後終止線程池
		Thread.sleep(1000L);
		List<Runnable> shutdownNow = threadPoolExecutor.shutdownNow();
		// 再次提交提示失敗
		threadPoolExecutor.submit(new Runnable() {
			@Override
			public void run() {
				System.out.println("追加一個任務");
			}
		});
		System.out.println("未結束的任務有:" + shutdownNow.size());

		// 結果分析
		// 1、 10個任務被執行,3個任務進入隊列等待,2個任務被拒絕執行
		// 2、調用shutdownnow後,隊列中的3個線程不再執行,10個線程被終止
		// 3、 追加的任務在線程池關閉後,無法再提交,會被拒絕執行
	}

	public static void main(String[] args) throws Exception {
//		new Demo9().threadPoolExecutorTest1();
//		new Demo9().threadPoolExecutorTest2();
//		new Demo9().threadPoolExecutorTest3();
//		new Demo9().threadPoolExecutorTest4();
//		new Demo9().threadPoolExecutorTest5();
//		new Demo9().threadPoolExecutorTest6();
//		new Demo9().threadPoolExecutorTest7();
		new Demo9().threadPoolExecutorTest8();
	}
}

發佈了49 篇原創文章 · 獲贊 20 · 訪問量 7591
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章