SimpleThreadPool实践
前言
并发(Concurrency)一直谈论java绕不开的一个话题,从移动开发工程师到后端工程师,几乎所有的面试都要涉及到并发/多线程的一些问题。虽然多数时候我们使用线程池,都是已经实现好的框架——jdk7中就有现成的ThreadPoolExecutor供我们使用,不过,自己实现一个简化的线程池,对于帮助我们理解其内部原理还是有一些帮助的。
设计
核心思想如下:
- 线程池实例为单例
- 线程池实例中保存着一个线程数组,用来分发任务
- 线程池中通过一个BlockingQueue实例,来实现FIFO的任务队列,这个实例同时被线程数组中的每一个线程拥有
- 线程通过while循环,不断从队列中取出任务执行(Runnable

实现
首先是线程池示例SimpleThreadPool.java,使用单例模式。
public class SimpleThreadPool {
private static SimpleThreadPool ourInstance;
private static final int QUEUE_SIZE = 100; // todo 调整 最优的capacity
private PoolThread[] threadArray;
private BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(QUEUE_SIZE);
private boolean isStopped;
public static SimpleThreadPool getInstance() {
if (ourInstance == null) {
ourInstance = new SimpleThreadPool();
}
return ourInstance;
}
public SimpleThreadPool initPoolSize(int size) {
if (size < 1 || size > 10) {
throw new RuntimeException("size must be 1~10!");
}
threadArray = new PoolThread[size];
for (int i = 0; i < size; i++) {
threadArray[i] = new PoolThread(blockingQueue);
threadArray[i].start();
}
return this;
}
public synchronized SimpleThreadPool execute(Runnable runnable) {
if (isStopped) {
throw new IllegalStateException("Thread Pool is stopped!");
}
blockingQueue.offer(runnable);
return this;
}
public synchronized void doStop() {
for (PoolThread pt : threadArray) {
pt.doStop();
}
isStopped = true;
}
}
然后是自定义的线程池线程,PoolThread.java
是否需要在run、doStop两个方法前声明synchronized,存疑。
public class PoolThread extends Thread {
private BlockingQueue<Runnable> blockingQueue;
private boolean isStopped;
public PoolThread(BlockingQueue<Runnable> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
while (!isStopped) {
try {
Runnable runnable = blockingQueue.take();
System.out.println(getName() + " is running...");
runnable.run();
} catch (InterruptedException e) {
// todo: log it
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public void doStop() {
interrupt();
isStopped = true;
}
}
写个Main函数测试一下。
public class Main {
public static void main(String[] args) {
SimpleThreadPool.getInstance().initPoolSize(10).execute(new Runnable() {
@Override
public void run() {
System.out.println("1+1=" + (1 + 1));
}
}).execute(new Runnable() {
@Override
public void run() {
System.out.println("2+2=" + (2 + 2));
}
}).execute(new Runnable() {
@Override
public void run() {
System.out.println("3+3=" + (3 + 3));
}
}).execute(new Runnable() {
@Override
public void run() {
System.out.println("4+4=" + (4 + 4));
}
}).execute(new Runnable() {
@Override
public void run() {
System.out.println("5+5=" + (5 + 5));
}
})
;
SimpleThreadPool.getInstance().doStop();
}
}
示例输出:
Thread-9 is running...
1+1=2
Thread-9 is running...
2+2=4
Thread-9 is running...
3+3=6
Thread-3 is running...
4+4=8
Thread-4 is running...
5+5=10
SimpleThreadPool实践的更多相关文章
- Quartz应用实践入门案例一(基于Web环境)
Quartz是一个完全由java编写的开源作业调度框架,正是因为这个框架整合了许多额外的功能,所以在使用上就显得相当容易.只是需要简单的配置一下就能轻松的使用任务调度了.在Quartz中,真正执行的j ...
- spring-boot-2.0.3之quartz集成,最佳实践
前言 开心一刻 快过年了,大街上,爷爷在给孙子示范摔炮怎么放,嘴里还不停念叨:要像这样,用劲甩才能响.示范了一个,两个,三个... 孙子终于忍不住了,抱着爷爷的腿哭起来:爷呀,你给我剩个吧! 新的一年 ...
- spring-boot-starter-quartz集群实践
[**前情提要**]由于项目需要,需要一个定时任务集群,故此有了这个spring-boot-starter-quartz集群的实践.springboot的版本为:2.1.6.RELEASE:quart ...
- webp图片实践之路
最近,我们在项目中实践了webp图片,并且抽离出了工具模块,整合到了项目的基础模板中.传闻IOS10也将要支持webp,那么使用webp带来的性能提升将更加明显.估计在不久的将来,webp会成为标配. ...
- Hangfire项目实践分享
Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...
- TDD在Unity3D游戏项目开发中的实践
0x00 前言 关于TDD测试驱动开发的文章已经有很多了,但是在游戏开发尤其是使用Unity3D开发游戏时,却听不到特别多关于TDD的声音.那么本文就来简单聊一聊TDD如何在U3D项目中使用以及如何使 ...
- Logstash实践: 分布式系统的日志监控
文/赵杰 2015.11.04 1. 前言 服务端日志你有多重视? 我们没有日志 有日志,但基本不去控制需要输出的内容 经常微调日志,只输出我们想看和有用的 经常监控日志,一方面帮助日志微调,一方面及 ...
- 【大型网站技术实践】初级篇:借助Nginx搭建反向代理服务器
一.反向代理:Web服务器的“经纪人” 1.1 反向代理初印象 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从 ...
- Windows平台分布式架构实践 - 负载均衡
概述 最近.NET的世界开始闹腾了,微软官方终于加入到了对.NET跨平台的支持,并且在不久的将来,我们在VS里面写的代码可能就可以通过Mono直接在Linux和Mac上运行.那么大家(开发者和企业)为 ...
随机推荐
- TCP SYN扫描学习笔记
1.TCP SYN包扫描主机状态的原理:tcp协议规定,当目标主机收到一个tcp syn 包时,若目标主机处于开放状态,会返回给源主机一个tcp ack 包(目的端口开放),或者向源主机发送一个tcp ...
- VS常用快捷键
智能提示:ctrl + J方法参数提示:ctrl + shift +空格智能标记(如:提示using.实现接口.抽象类等):ctrl + .执行测试:ctrl + R,T(当前上下文),ctrl + ...
- C#连接数据库SQL,并转换成list形式
web config 配置 <connectionStrings> <add name="SQLConnString" connectionString=& ...
- 通过sougou输入法,解决卡在Setup Wizard(小绿人)界面
本人使用海信EG900手机(安卓2.3.5,已root),为了使用google的服务,先后手动复制和CWM recovery刷入google服务包(gapps-gb-20110828-signed.z ...
- UVA 101
题意:四种操作把a和b所在的数字移动. lrj的思想很好.首先找到共同点.然后不必写四种操作.其次理解vector的方便. #include<iostream> #include<c ...
- 3d数学总结帖
3d数学总结帖,以下是对3d学习过程中数学知识的简单总结 角度值和弧度制的互转 Deg2Rad 角度A1转弧度A2 => A2=A1*PI/180 Rad2Deg 弧度A2转换角度A1 => ...
- 使用RXTX获取电脑串口
RXTX是javacomm串口通信的一个扩展 RXTX开发所需文件的下载地址:http://rxtx.qbang.org/wiki/index.php/Download 解压之后可以看到支持各个平台的 ...
- mysql 基础列题
1:emp表中查询公司总共有几个部门注意,会查询出来大量重复的,使用函数distinctselect distinct job from scott.emp; 2:查询公司工资在1000-3000之间 ...
- (译) Conditional Variational Autoencoders 条件式变换自编码机
Conditional Variational Autoencoders --- 条件式变换自编码机 Goal of a Variational Autoencoder: 一个 VAE(variati ...
- 怎么使用CDR中排列对象功能
通过将对象发送到其他对象的前面或者后面,可以更改图层或页面上对象的堆叠顺序,还可以将对象按堆叠顺序精确定位,并且可以反转多个对象的堆叠顺序.本教程将详解CorelDRAW中排列对象各按钮功能. 1. ...