Java手写线程池-第一代(原创)
个人简介
作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。
文章目录
- 个人简介
- Java手写线程池(第一代)
- 手写线程池-定义参数
- 手写线程池-构造器
- 手写线程池-默认构造器
- 手写线程池-execute方法
- 手写线程池-处理任务
- 手写线程池-优雅关闭线程池
- 手写线程池-暴力关闭线程池
- 手写线程池-源代码
- 手写线程池类的源代码
- 测试使用手写线程池代码
- 问题:为什么自定义线程池的execute执行的任务有时会变少?
Java手写线程池(第一代)
- 经常使用线程池,故今天突发奇想,手写一个线程池,会有很多不足,请多多宽容。因为这也是第一代的版本,后续会更完善。
手写线程池-定义参数
private final AtomicInteger taskcount=new AtomicInteger(0);private final AtomicInteger threadNumber=new AtomicInteger(0);private volatile int corePoolSize; private final Set<MyThreadPoolExecutor.MyWorker> workers; private final BlockingQueue<Runnable> waitingQueue; private final String THREADPOOL_NAME="MyThread-Pool-";private volatile boolean isRunning=true; private volatile boolean STOPNOW=false; private final ThreadFactory threadFactory;
taskcount:执行任务次数
threadNumber:线程编号,从0开始依次递增。
corePoolSize:核心线程数
workers:工作线程
waitingQueue:等待队列
THREADPOOL_NAME:线程名称
isRunning:是否运行
STOPNOW:是否立刻停止
threadFactory:线程工厂
手写线程池-构造器
public MyThreadPoolExecutor(int corePoolSize, BlockingQueue<Runnable> waitingQueue,ThreadFactory threadFactory) {this.corePoolSize=corePoolSize;this.workers=new HashSet<>(corePoolSize);this.waitingQueue=waitingQueue;this.threadFactory=threadFactory;//线程预热for (int i = 0; i < corePoolSize; i++) {new MyWorker();}}
- 该构造器作用:
- 1:对参数进行赋值。
- 2:线程预热。根据corePoolSize的大小来调用MyWorker的构造器。我们可以看看MyWorker构造器做了什么。
final Thread thread; //为每个MyWorkerMyWorker(){Thread td = threadFactory.newThread(this);td.setName(THREADPOOL_NAME+threadNumber.getAndIncrement());this.thread=td;this.thread.start();workers.add(this);}
- MyWorker构造器通过线程工厂对当前对象生成Thread;
- 并设置线程名为:MyThread-Pool-自增线程编号;
- 然后调用线程的start方法启动线程;
- 最后存放在workers这个Set集合中,这样就可以实现线程复用了。
手写线程池-默认构造器
public MyThreadPoolExecutor(){this(5,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory());}
- 默认构造器的赋初始值:
- corePoolSize:5
- waitingQueue:new ArrayBlockingQueue<>(10),长度为10的有限阻塞队列
- threadFactory:Executors.defaultThreadFactory()
手写线程池-execute方法
public boolean execute(Runnable runnable){return waitingQueue.offer(runnable);}
- 本质上其实就是把Runnable(任务)放到waitingQueue中。
手写线程池-处理任务
@Overridepublic void run() {//循环接收任务while (true){if((!isRunning&&waitingQueue.size()==0)||STOPNOW){break;}else {Runnable runnable = waitingQueue.poll();if(runnable!=null){runnable.run();System.out.println("task==>"+taskcount.incrementAndGet());}}}}
- 本质上就是一个死循环接收任务,退出条件如下:
- 1:优雅的退出。当isRunning为false并且waitingQueue的队列大小为0(也就是无任务了)
- 2:暴力退出。当STOPNOW为true,则说明调用了shutdownNow方法
- else语句块会不断取任务,当任务!=null时则调用run方法处理任务
手写线程池-优雅关闭线程池
public void shutdown(){this.isRunning=false;}
手写线程池-暴力关闭线程池
public void shutdownNow(){this.STOPNOW=true;}
手写线程池-源代码
手写线程池类的源代码
package com.springframework.concurrent;import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;/*** 线程池类* @author 游政杰*/
public class MyThreadPoolExecutor {private final AtomicInteger taskcount=new AtomicInteger(0);//执行任务次数private final AtomicInteger threadNumber=new AtomicInteger(0); //线程编号private volatile int corePoolSize; //核心线程数private final Set<MyThreadPoolExecutor.MyWorker> workers; //工作线程private final BlockingQueue<Runnable> waitingQueue; //等待队列private final String THREADPOOL_NAME="MyThread-Pool-";//线程名称private volatile boolean isRunning=true; //是否运行private volatile boolean STOPNOW=false; //是否立刻停止private final ThreadFactory threadFactory; //线程工厂public MyThreadPoolExecutor(){this(5,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory());}public MyThreadPoolExecutor(int corePoolSize, BlockingQueue<Runnable> waitingQueue,ThreadFactory threadFactory) {this.corePoolSize=corePoolSize;this.workers=new HashSet<>(corePoolSize);this.waitingQueue=waitingQueue;this.threadFactory=threadFactory;//线程预热for (int i = 0; i < corePoolSize; i++) {new MyWorker();}}/*** MyWorker就是我们每一个线程对象*/private final class MyWorker implements Runnable{final Thread thread; //为每个MyWorkerMyWorker(){Thread td = threadFactory.newThread(this);td.setName(THREADPOOL_NAME+threadNumber.getAndIncrement());this.thread=td;this.thread.start();workers.add(this);}@Overridepublic void run() {//循环接收任务while (true){//循环退出条件://1:当isRunning为false并且waitingQueue的队列大小为0(也就是无任务了),会优雅的退出。//2:当STOPNOW为true,则说明调用了shutdownNow方法进行暴力退出。if((!isRunning&&waitingQueue.size()==0)||STOPNOW){break;}else {//不断取任务,当任务!=null时则调用run方法处理任务Runnable runnable = waitingQueue.poll();if(runnable!=null){runnable.run();System.out.println("task==>"+taskcount.incrementAndGet());}}}}}public boolean execute(Runnable runnable){return waitingQueue.offer(runnable);}//优雅的关闭public void shutdown(){this.isRunning=false;}//暴力关闭public void shutdownNow(){this.STOPNOW=true;}
}
测试使用手写线程池代码
package com.springframework.test;import com.springframework.concurrent.MyThreadPoolExecutor;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;public class ThreadPoolTest {public static void main(String[] args) {MyThreadPoolExecutor myThreadPoolExecutor = new MyThreadPoolExecutor(5,new ArrayBlockingQueue<>(6), Executors.defaultThreadFactory());for(int i=0;i<10;i++){int finalI = i;myThreadPoolExecutor.execute(()->{System.out.println(Thread.currentThread().getName()+">>>>"+ finalI);});}myThreadPoolExecutor.shutdown();// myThreadPoolExecutor.shutdownNow();}
}
问题:为什么自定义线程池的execute执行的任务有时会变少?
- 那是因为waitingQueue满了放不下任务了,导致任务被丢弃,相当于DiscardPolicy拒绝策略
- 解决办法有:
- 1:设置最大线程数,自动对线程池扩容。
- 2:调大waitingQueue的容量capacity
最后:因为这是我手写的线程池的初代版本,基本实现线程池的复用功能,然而还有很多未完善,将来会多出几篇完善后的文章,对目前手写的线程池进行升级。
后续还会继续出关于作者手写Spring框架,手写Tomcat等等框架的博文!!!!!
Java手写线程池-第一代(原创)相关推荐
- Java手写线程池(不带返回值、带返回值)
文章目录 不带返回值 带返回值 不带返回值 public class MyThreadPool {private static final int DEFAULT_THREAD_NUM = 10;pr ...
- C++ 中的多线程的使用和线程池建设。150行代码,手写线程池
C++ 11 引入了 std::thread 标准库,方便了多线程相关的开发工作. 说到多线程开发,可不仅仅是创建一个新线程就好了,不可避免的要涉及到线程同步的问题. 而保证线程同步,实现线程安全,就 ...
- 【线程池】自行准备linux环境,带你手写线程池,只需仅仅150行代码|内存池|API|连接池|应用协议丨C/C++Linux服务器开发
[线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码 视频讲解如下,点击观看: [线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码|内存池|API|连接池|应用协 ...
- 【线程池】自行准备linux环境,带你手写线程池,只需仅仅150行代码
[线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码 视频讲解如下,点击观看: [线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码|内存池|API|连接池|应用协 ...
- java 手编线程池_死磕 java线程系列之自己动手写一个线程池
欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. (手机横屏看源码更方便) 问题 (1)自己动手写一个线程池需要考虑哪些因素? (2)自己动手写 ...
- Java web项目创建笔记28 之《手写线程池》
1.原理 线程池核心点----复用机制 1)提前创建好固定的线程一直在运行状态----死循环实现 2)提交的线程任务缓存到一个并发队列集合中,交给正在运行的线程执行 3)正在运行的线程从队列中获取该任 ...
- 面经手册 · 第21篇《手写线程池,对照学习ThreadPoolExecutor线程池实现原理!》
作者:小傅哥 博客:https://bugstack.cn Github:https://github.com/fuzhengwei/CodeGuide/wiki 沉淀.分享.成长,让自己和他人都能有 ...
- 手撕线程池 ThreadPool
为了更加方便理解线程池 我们都知道线程池和任务就好比生产者消费者之间的关系也就是如图! 先分析:我们可以将线程池中的线程看作消费者,可以将main(只是方便测试)看作生产者 总体思路: 实现一个阻塞队 ...
- Java多线程之线程池的手写改造和拒绝策略
Java多线程之线程池的手写改造和拒绝策略 目录 自定义线程池的使用 四种拒绝策略代码体现 1. 自定义线程池的使用 自定义线程池(拒绝策略默认AbortPolicy) public class My ...
最新文章
- Effectice Java之始终覆盖toString(十)
- Emmet使用-----HTML
- springboot:记录jdbc
- 电商5个流程的用户体验
- java实现调查问卷_智能办公进行时丨富士施乐邀您参与有奖问卷调查
- AttributeError: module ‘torch.onnx‘ has no attribute ‘set_training‘
- python控制电机转动_Micropython TurnipBit 旋转按钮控制直流电机转速(儿时记忆中的吊扇)...
- msxml6_x64 下载
- Java编程思想 - 并发
- 把已有项目转换成Visual Studio的解决方案
- 日志宝:大众也能看懂的Web访问日志数据分析
- 获取微信昵称乱码php,Android 微信登录昵称乱码问题,及获取微信用户信息
- 神经网络低比特量化——LSQ
- 怎样计算系统的可靠性和可用性是几个9?
- [SDOI2013] 淘金
- Opencv Surf特征实现图像无缝拼接生成全景图像(三)
- python贪心算法最短路径_dijkstra算法(贪心算法)——解决最短路径问题
- 网络直播电视之M3U8解析篇(上)
- vs2017添加C语言模版,「vs2017 项目模板」有没有大神知道vs2017怎么配置wdk10开发x64驱动...
- [pig框架实战] 手撕视频管理发布平台[02] - pig框架源码分析(去除开发过程中每次输入验证码的过程,方便快速登录)