说明

手写的一个简单的线程池,旨在帮助了解线程池的工作原理。

核心内容

  1. 核心工作线程
  2. 任务阻塞队列

定义一个内部类去实现核心工作线程

    /*** 内部类:工作的核心线程*/private final class WorkerThread extends Thread {String name;//构造方法WorkerThread(String name) {this.name = name;}@Overridepublic void run() {while (!getPoolState()) {try {Runnable task = taskQueue.take();if (task != null) {getThreadLog("任务开始执行:" + task.toString());task.run();}//释放内存task = null;} catch (Exception e) {e.printStackTrace();}}System.out.println("线程关闭");}}

使用一个阻塞队列存放需要处理的任务列表

    //存放任务执行结束的队列private volatile BlockingQueue<Runnable> taskQueue;//记录线程池中线程的个数private final Set<WorkerThread> workerThreadSet = new HashSet<>();

完整测试代码

package com.leo.demo.threadtest.mythreadpool;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;/*** @ClassName: MyThreadPool* @Description: 小的线程池模型* 1、线程池的* @Author: leo825* @Date: 2020-05-11 23:08* @Version: 1.0*/
public class MyThreadPool {//核心线程数private int corePoolSize;//最大线程数private int maximumPoolSize;//存放任务执行结束的队列private volatile BlockingQueue<Runnable> taskQueue;//记录线程池中线程的个数private final Set<WorkerThread> workerThreadSet = new HashSet<>();//当前存放当前线程数private int workerCount = 0;//线程池关闭状态private volatile boolean THREADPOOL_SHUTDOWN = false;/*** 线程池构造方法,先不考虑参数校验问题** @param corePoolSize* @param maximumPoolSize* @param taskQueue*/MyThreadPool(int corePoolSize, int maximumPoolSize, BlockingQueue<Runnable> taskQueue) {this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.taskQueue = taskQueue;//构造线程池中的线程for (int i = 0; i < corePoolSize; i++) {WorkerThread workerThread = new WorkerThread("poolThread_" + i);workerThread.start();workerThreadSet.add(workerThread);workerCount++;}}/*** 向线程池中提交任务执行结束** @param task*/public void submit(Runnable task) {if (taskQueue.offer(task)) {getThreadLog("任务执行结束添加成功: " + task.toString());} else {getThreadLog("任务执行结束添加失败: " + task.toString());}}/*** 关闭线程池*/public void shutdown() {getThreadLog("关闭线程池");THREADPOOL_SHUTDOWN = true;}/*** 内部类:工作的核心线程*/private final class WorkerThread extends Thread {String name;//构造方法WorkerThread(String name) {this.name = name;}@Overridepublic void run() {while (!THREADPOOL_SHUTDOWN) {try {Runnable task = taskQueue.take();if (task != null) {getThreadLog("任务开始执行:" + task.toString());task.run();}//释放内存task = null;} catch (Exception e) {e.printStackTrace();}}getThreadLog("线程关闭");}}/*** 获取线程名和时间** @return*/public static void getThreadLog(String logContent) {StringBuffer stringBuffer = new StringBuffer();stringBuffer.append("[");stringBuffer.append(Thread.currentThread().getName());stringBuffer.append(" ");stringBuffer.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));stringBuffer.append("] ");stringBuffer.append(logContent);System.out.println(stringBuffer.toString());}/*** 测试main方法** @param args*/public static void main(String[] args) throws InterruptedException {//定义一个阻塞队列存放任务BlockingQueue<Runnable> workQueue = new LinkedBlockingDeque<>(5);//构造自己的线程池MyThreadPool threadPool = new MyThreadPool(3, 5, workQueue);//任务执行结束数量int size = 15;for (int i = 0; i < size; i++) {threadPool.submit(new Runnable() {@Overridepublic void run() {try {int times = ThreadLocalRandom.current().nextInt(2, 6);TimeUnit.SECONDS.sleep(times);getThreadLog("任务执行结束 " + this.toString() + ",执行时长:" + times + " 秒");} catch (InterruptedException e) {e.printStackTrace();}}});}//休息20秒TimeUnit.SECONDS.sleep(20);//关闭线程池,此处不管用的,待后续分析源码threadPool.shutdown();}
}

测试结果如下:

[Thread-0 2020-06-09 11:32:12.698] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@3fee733d
[main 2020-06-09 11:32:12.696] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@3fee733d
[main 2020-06-09 11:32:12.699] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@2a84aee7
[main 2020-06-09 11:32:12.699] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@a09ee92
[main 2020-06-09 11:32:12.699] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@30f39991
[main 2020-06-09 11:32:12.700] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@452b3a41
[main 2020-06-09 11:32:12.700] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@4a574795
[main 2020-06-09 11:32:12.700] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@f6f4d33
[main 2020-06-09 11:32:12.701] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@23fc625e
[main 2020-06-09 11:32:12.701] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@3f99bd52
[main 2020-06-09 11:32:12.701] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@4f023edb
[main 2020-06-09 11:32:12.702] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@3a71f4dd
[main 2020-06-09 11:32:12.703] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@7adf9f5f
[main 2020-06-09 11:32:12.703] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@85ede7b
[main 2020-06-09 11:32:12.703] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@5674cd4d
[main 2020-06-09 11:32:12.704] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@63961c42
[Thread-1 2020-06-09 11:32:12.709] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@2a84aee7
[Thread-2 2020-06-09 11:32:12.711] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@a09ee92
[Thread-0 2020-06-09 11:32:14.712] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@3fee733d,执行时长:2 秒
[Thread-0 2020-06-09 11:32:14.714] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@30f39991
[Thread-1 2020-06-09 11:32:16.710] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@2a84aee7,执行时长:4 秒
[Thread-1 2020-06-09 11:32:16.711] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@452b3a41
[Thread-2 2020-06-09 11:32:17.712] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@a09ee92,执行时长:5 秒
[Thread-2 2020-06-09 11:32:17.712] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@4a574795
[Thread-0 2020-06-09 11:32:17.715] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@30f39991,执行时长:3 秒
[Thread-1 2020-06-09 11:32:19.711] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@452b3a41,执行时长:3 秒
[Thread-2 2020-06-09 11:32:21.713] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@4a574795,执行时长:4 秒
[main 2020-06-09 11:32:32.704] 关闭线程池

问题和思考

以上就是一个很小的线程池的模型,这个模型还存在很多问题。

  1. 线程池的最大线程数是核心线程满、阻塞队列满之后线程池扩展到最大线程数,线程池扩容是如何实现的?
  2. 线程空闲后是如何进行销毁的?
  3. 线程池相关的监控指标,历史最大线程数、当前线程数、累计执行任务数?
  4. 线程池是如何销毁的?
  5. 如果taskQueue队列满了,如何管理容量?
  6. 如果taskQueue中没有任务了,线程池活跃线程数如何看?

手写一个简单的线程池MyThreadPool相关推荐

  1. 如何写一个高效进程/线程池_关于高效企业测试的思考(1/6)

    如何写一个高效进程/线程池 企业中的测试仍然没有得到应有的广泛应用. 编写尤其是维护测试需要花费时间和精力,但是缩短软件测试并不是解决方案. 为了提高测试效率,应该追求哪些范围,方法和测试技术? 基于 ...

  2. 分享:一个简单的线程池的实现

    一个简单的线程池的实现 http://my.oschina.net/hejiula/blog/110519

  3. 一个简单的线程池设计方案

    一个简单的线程池本质上是生产者-消费者模型,一般是线程池负责消费任务,任务分配线程负责生产任务,任务可以由队列.链表或全局变量等数据结构承担.如果生产和消费速度差不多,可以采用环形队列结构:如果任务有 ...

  4. 手写一个简单的IOC容器

    手写一个简单的IOC容器 原文 http://localhost:4000/2020/02/25/SSM/spring/%E6%89%8B%E5%86%99%E4%B8%80%E4%B8%AA%E5% ...

  5. jquery手写轮播图_用jQuery如何手写一个简单的轮播图?(附代码)

    用jQuery如何手写一个简单的轮播图?下面本篇文章通过代码示例来给大家介绍一下.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. 用 jQuery 手写轮播图 先上个效果截图: 主要 ...

  6. 怎么手写一个简单的List集合

    List集合 手写一个简单的List集合为自己调用并不是特别难,只需要定义一个集合接口去提供所有方法的定义如下代码 : package com.myself.util; /*** * @author ...

  7. 手写一个简单的分页器

    封装分页器 1. 前言 分页器基本上是任何网站必须要有的一个组件,为什么需要分页器,当后台传入了大量的数据,那么在前端拿到数据,如果直接展示很有可能或造成卡顿,同时消耗过多的内存,给用户带来的浏览效果 ...

  8. 【Java】远程调用、线程池手写一个简单服务器

    " 关键字:远程调用.序列化.反序列化.反射.动态代理.客户端.服务端.线程池 > 思考题:带着这几个问题可以先思考,然后看完文章再去理解,也可以在评论区讨论喔~ 反射和动态代理关系和 ...

  9. Linux下设计一个简单的线程池

    定义 什么是线程池?简单点说,线程池就是有一堆已经创建好了的线程,初始它们都处于空闲等待状态,当有新的任务需要处理的时候,就从这个池子里面取一个空闲等待的线程来处理该任务,当处理完成了就再次把该线程放 ...

最新文章

  1. 深入理解JVM文章合集
  2. 数据结构实验之排序二:交换排序
  3. 【学习Spring框架】依赖注入和控制反转异同?
  4. Abaqus单位制简述
  5. IEEE1588v2解析(7)gPTP协议和PTP的关系
  6. WhatsApp翻译器 — tranworld翻译助手,ZALO LINE KaKao badoo buble tiktok facebook 社交聊天软件一键自动双向即时翻译
  7. jetpack之workManager官方文档解析
  8. besiege机器人_《围攻》双脚机器人制作图文教程 双脚机器人怎么制作
  9. 如何制作网络视频投票?
  10. 基于JSP实现医院病历管理系统,程序员如何在工作中自我增值
  11. 【未完成】常微分实验3.3:解 连续的初值 可微性定理
  12. 【例题 8-4 UVA - 11134】Fabled Rooks
  13. STL文件模型体积计算
  14. 软件项目管理系统-采购商品管理-采购一览
  15. 游戏开发技术Unity开发引擎
  16. vite.config.ts找不到模块“path”或其相应的类型声明
  17. 智能数据可视化-雷达图的使用方法
  18. 精致少女动漫人物怎么画?美术集分享最基础简单的动漫画法~
  19. 超市订单管理系统(SMBMS):盘点管理
  20. python拟合三元函数_python基础教程之常用内置函数、三元运算、递归

热门文章

  1. BAPI_SALESORDER_CREATEFROMDAT2 BAPI创建VA01 销售订单
  2. SAP复合角色更改后扩展到派生节点
  3. 关于ABST2的若干问题
  4. 项目中用到的BAPI合集
  5. 2021年有不加班的选择吗?哪些城市加班最严重?
  6. 技巧速看!如何帮助“表哥”快速玩转报告美化?
  7. 变革后的维密,做了一款不赚钱的内衣
  8. 社区团购的终局会是近景零售版的拼多多吗?
  9. cisco 交换机 定期 自动 备份配置 -linux,交换机定时自动备份配置文件的方法
  10. 数学不好的人可以学python吗_哪些人适合学金融工程专业 数学不好能学吗