手写线程池的实现、创建、执行任务、销毁

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

猜你喜欢

转载自www.cnblogs.com/jtfr/p/10507900.html