1.線程池實現的思維導圖,如果不理解JDK中線程池實現原理,看鏈接博客中末尾對線程池的原理的描述
https://www.cnblogs.com/jtfr/p/10187419.html

2.定義接口
1 package com.jtfr.core; 2 3 /** 4 * 線程池必須實現的接口 5 * @author 陳康明 qq:1123181523 6 * @date 2019年3月10日 7 */ 8 public interface Executer { 9 10 /** 11 * 添加工作方法 12 */ 13 void execute(Runnable runnable); 14 }
3.線程池實現類
1 package com.jtfr.core; 2 3 import java.util.Date; 4 import java.util.LinkedList; 5 import java.util.List; 6 7 8 public class ThreadPool implements Executer { 9 10 // 設置默認開啟線程個數 5 個 11 private int workerNumber = 5; 12 13 //線程工作組 14 WorkerThread[] workThreads; 15 16 //任務隊列 用個 list 后面添加方法用同步鎖定就行 17 private List<Runnable> taskQueue = new LinkedList<Runnable>(); 18 19 20 public ThreadPool(int workerNumber){ 21 // 小於零 說明輸入錯誤,就不賦值,使用默認值。 22 if (workerNumber > 0) { 23 this.workerNumber = workerNumber; 24 } 25 // 開啟工作空間, 注意:要用成員變量 26 workThreads = new WorkerThread[this.workerNumber]; 27 // 循環創建所有線程, 注意:要用成員變量 28 for (int i = 0; i < this.workerNumber; i++) { 29 // 創建的線程添加到 工作組 中 30 workThreads[i] = new WorkerThread(); 31 // 創建的線程開啟, 並且命名 (創建了多個線程池名稱可能會沖突,后面再看了) 32 new Thread(workThreads[i], "ThreadPool-worker " +(i+1)).start(); 33 System.out.println("初始化線程數" + (i + 1)); 34 } 35 } 36 37 /** 38 * 添加任務方法,即把對象添加到 隊列中, 同時喚醒所有 wait中的線程 39 */ 40 @Override 41 public void execute(Runnable task) { 42 synchronized (taskQueue) { 43 taskQueue.add(task); 44 taskQueue.notifyAll(); 45 } 46 } 47 48 /** 49 * 銷毀線程池,默認是等待線程執行完了再銷毀 50 */ 51 public void destory(){ 52 destory(true); 53 } 54 55 /** 56 * 銷毀線程池,可以指定不執行隊列中剩下的任務,直接銷毀線程池了。 57 * true表示繼續執行剩下的任務。 58 */ 59 public void destory(boolean isRunTask){ 60 // 默認是等待線程執行完了再銷毀 61 if (isRunTask) { 62 //循環是否還存在任務,如果存在等待20毫秒處理時間 63 while (!taskQueue.isEmpty()) { 64 try { 65 Thread.sleep(20); 66 } catch (InterruptedException e) { 67 e.printStackTrace(); 68 } 69 } 70 } 71 //如果任務隊列已處理完成,銷毀線程,清空任務 72 for (int i = 0; i < workerNumber; i++) { 73 workThreads[i].setIsRunning(); 74 workThreads[i] = null; 75 System.out.println("線程池銷毀了"); 76 } 77 taskQueue.clear(); 78 // 不能設置 taskQueue==null 其他正在調用的地方可能報 null指針異常。 79 //taskQueue = null; 80 } 81 82 /** 83 * 內部類:做線程工作類 84 */ 85 class WorkerThread implements Runnable{ 86 87 // 當前線程是否可用 88 private Boolean isRunning = true; 89 @Override 90 public void run() { 91 Runnable runnable = null; 92 // 死循環,除非外界調用銷毀方法,設定 isRunning 為false 93 while(isRunning){ 94 // 上面用的list 非線程安全,所以這里要同步去任務 95 synchronized (taskQueue) { 96 // 如果線程活的,但是 taskQueue 是空,線程等待 20 毫秒 97 while(isRunning && taskQueue.isEmpty()){ 98 try { 99 // wait會釋放鎖,其他工作線程可以繼續執行同步代碼塊里面內容。 100 taskQueue.wait(20); 101 } catch (InterruptedException e) { 102 e.printStackTrace(); 103 } 104 } 105 // 獲取任務,注意:要在同步代碼塊里面獲取任務。 106 // 為什么還要判斷 taskQueue 非空? 107 // 等待20毫秒,有任務能獲取到。 108 if (!taskQueue.isEmpty()) { 109 // list模擬隊列,所以獲取第一個元素。 110 runnable = taskQueue.remove(0); 111 } 112 } 113 // 注意:執行任務要在同步代碼塊外面,把鎖釋放出來給其他線程。 114 // 判斷 runnable ,因為可能沒有獲取到任務。 115 if (runnable != null) { 116 // 執行 run 方法,要任務實現Runnable接口,實際上是為了保證有 run 方法,和線程沒關系。 117 runnable.run(); 118 } 119 // 結束后置 null 方便回收。 120 runnable = null; 121 } 122 } 123 /** 124 * 銷毀線程,實際上就是不再死循環,正常結束了工作線程。 125 */ 126 public void setIsRunning(){ 127 this.isRunning = false; 128 } 129 130 } 131 132 }
4.測試類
1 package com.jtfr.test; 2 3 import com.jtfr.core.ThreadPool; 4 5 public class TestMain { 6 7 public static void main(String[] args) { 8 ThreadPool threadPool = new ThreadPool(-5); 9 for (int i = 0; i < 100; i++) { 10 threadPool.execute(new Thread(new Runnable() { 11 @Override 12 public void run() { 13 System.out.println(Thread.currentThread().getName()); 14 try { 15 Thread.sleep(1000); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 } 20 })); 21 } 22 // 調用銷毀方法,不執行剩下的任務 23 threadPool.destory(false); 24 } 25 }
5.擴展
https://www.cnblogs.com/jtfr/p/10507437.html
1 package com.jtfr.test; 2 3 import java.text.SimpleDateFormat; 4 import java.util.ArrayList; 5 import java.util.Date; 6 import java.util.List; 7 8 9 /** 10 * 測試 wait和sleep方法 11 * 按照網上說的:wait會釋放鎖,sleep不會釋放鎖,寫個案例執行下。 12 * @author 陳康明 qq:1123181523 13 * @date 2019年3月10日 14 */ 15 public class TestWait { 16 17 private static List<String> list = new ArrayList<String>(); 18 19 public static void main(String[] args) { 20 TestWait test = new TestWait(); 21 WaitSleep w1 = test.new WaitSleep(); 22 WaitSleep w2 = test.new WaitSleep(); 23 WaitSleep w3 = test.new WaitSleep(); 24 w1.start(); 25 w2.start(); 26 w3.start(); 27 } 28 29 class WaitSleep extends Thread{ 30 31 @Override 32 public void run() { 33 synchronized (list) { 34 try { 35 System.out.println(Thread.currentThread().getName()+"當前系統時間:"+new SimpleDateFormat("hh:mm:ss").format(new Date())); 36 // 等待 10 秒, 看其他對象是否拿到鎖 37 list.wait(10000); 38 //Thread.sleep(10000); 39 } catch (Exception e) { 40 e.printStackTrace(); 41 } 42 } 43 } 44 } 45 }
源碼
https://files.cnblogs.com/files/jtfr/JtfrThreadPool.rar
