手寫線程池的實現、創建、執行任務、銷毀


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

 


免責聲明!

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



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