线程池原理:手写简单的线程池

it2025-08-21  4

线程池原理:手写简单线程池

一、线程池作用

1.提高程序执行效率,并发执行提高响应速度;2.线程复用,减少频繁创建销毁线程对服务器的性能消耗3.有利于对线程进行管理

二、线程池基本的常见构成要素

1.执行的线程数量,开启执行的线程;2.执行的任务集合3.构造方法4.executor方法(有返回值)或submit方法(无返回值)5.shutdown停止线程的方法

参考简图:

三、手写简单线程池样例,有利于加深对线程池工作原理的理解

package com.demo.spring.test.threadPool; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; /** * @Description: 简单模拟手写线程池,方便理解线程池工作原理 * @Author: 狗狗大蛇 * @Date: */ public class MyThreadPoolExecutor { // 工作线程集合 private List<TaskThread> threads; // 阻塞队列:executor(Runnable 实参)传进来的工作任务均先存放到该队列中,等待TaskThread去取出来执行; private BlockingQueue<Runnable> workQueue; // 控制线程池停止的标记 private volatile Boolean shutDownFlag = true; /** * 线程池构造方法 * @param threadNum : 初始创建保持运行状态线程的数量 * @param works : 线程池处理的工作任务数量 */ public MyThreadPoolExecutor(int threadNum,int works){ // 创建指定大小的队列容器,用于存放任务; this.workQueue = new LinkedBlockingQueue<>(works); // 创建threadNum运行状态的线程数量,并进入就绪状态 this.threads = new ArrayList<>(); for(int i = 0 ; i < threadNum; i++){ TaskThread workThread = new TaskThread(); Thread thread = new Thread(workThread); thread.start(); this.threads.add(workThread); } } /** * 定义一个工作线程:也叫服务线程:指不断获取队列中的消息来进行处理的线程; * 1.在线程池中始终保持运行状态; * 2.不停的去工作任务队列中去取任务; */ class TaskThread implements Runnable{ @Override public void run() { // 1.如果要线程保持运行状态,需要写死循环 while (shutDownFlag){ // 2.队列中取任务执行,取完删掉对应任务; Runnable task = null; try { // 此处不用poll,poll会不停的取,导致CPU使用率居高不下;用take没有任务以后会等待,CPU使用率消耗特别低; task = workQueue.take(); } catch (InterruptedException e) { e.printStackTrace(); } if(null != task){ task.run(); } } } } /** * 线程池启动执行的方法 * @param runnable 放入需要执行的业务任务线程; * @return */ public void executor(Runnable runnable){ // 将业务线程放到队列容器中,运行中的线程会不停的到队列中取任务; // offer(): 非阻塞式添加任务 try { workQueue.put(runnable); } catch (InterruptedException e) { e.printStackTrace(); } } public void shutdown(){ this.shutDownFlag = false; } // 测试效果 public static void main(String[] args) throws InterruptedException { MyThreadPoolExecutor myThreadPoolExecutor = new MyThreadPoolExecutor(4,8); SendEmailTask sendEmailTask = new SendEmailTask(); boolean flag = false; for(int i = 0; i < 100; i++){ myThreadPoolExecutor.executor(sendEmailTask); if( i == 99 ){ flag = true; } } // 模拟等待10秒后又有新的任务调用线程 Thread.sleep(10000); System.out.println("模拟等待10秒"); myThreadPoolExecutor.executor(sendEmailTask); System.out.println("结束"); // 模拟等待10秒没有任务,停止线程 Thread.sleep(10000); if(flag){ myThreadPoolExecutor.shutdown(); } } } /** * @Description: 具体发送邮件的业务线程 * @Author: yangshilei * @Date: */ class SendEmailTask implements Runnable{ @Override public void run() { try { // 模拟实际业务处理占用的时间 Thread.sleep(new Random().nextInt(2000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程:"+Thread.currentThread().getName() + ":" + "短信发送成功"); } }

四、执行结果 我们可以看到已经实现了线程的复用: 且始终只有0,1,2,3这4开启的线程;

线程:Thread-3:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-3:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-0:短信发送成功 线程:Thread-1:短信发送成功 线程:Thread-2:短信发送成功 线程:Thread-3:短信发送成功 模拟等待10秒 结束 线程:Thread-0:短信发送成功

五、测试过程中发现CPU占用过高的问题以及处理方法 在使用poll()方法获取任务,导致CPU占用率很高,如下截图: 处理办法,将poll()换成take()进行获取任务,没有任务时候等待任务;测试代码中最后部分就是测试,等待后有新任务是否会生效的测试,如下代码和截图:

// 模拟等待10秒后又有新的任务调用线程 Thread.sleep(10000); System.out.println("模拟等待10秒"); myThreadPoolExecutor.executor(sendEmailTask); System.out.println("结束");

最新回复(0)