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