前言

并发(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实践的更多相关文章

  1. Quartz应用实践入门案例一(基于Web环境)

    Quartz是一个完全由java编写的开源作业调度框架,正是因为这个框架整合了许多额外的功能,所以在使用上就显得相当容易.只是需要简单的配置一下就能轻松的使用任务调度了.在Quartz中,真正执行的j ...

  2. spring-boot-2.0.3之quartz集成,最佳实践

    前言 开心一刻 快过年了,大街上,爷爷在给孙子示范摔炮怎么放,嘴里还不停念叨:要像这样,用劲甩才能响.示范了一个,两个,三个... 孙子终于忍不住了,抱着爷爷的腿哭起来:爷呀,你给我剩个吧! 新的一年 ...

  3. spring-boot-starter-quartz集群实践

    [**前情提要**]由于项目需要,需要一个定时任务集群,故此有了这个spring-boot-starter-quartz集群的实践.springboot的版本为:2.1.6.RELEASE:quart ...

  4. webp图片实践之路

    最近,我们在项目中实践了webp图片,并且抽离出了工具模块,整合到了项目的基础模板中.传闻IOS10也将要支持webp,那么使用webp带来的性能提升将更加明显.估计在不久的将来,webp会成为标配. ...

  5. Hangfire项目实践分享

    Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...

  6. TDD在Unity3D游戏项目开发中的实践

    0x00 前言 关于TDD测试驱动开发的文章已经有很多了,但是在游戏开发尤其是使用Unity3D开发游戏时,却听不到特别多关于TDD的声音.那么本文就来简单聊一聊TDD如何在U3D项目中使用以及如何使 ...

  7. Logstash实践: 分布式系统的日志监控

    文/赵杰 2015.11.04 1. 前言 服务端日志你有多重视? 我们没有日志 有日志,但基本不去控制需要输出的内容 经常微调日志,只输出我们想看和有用的 经常监控日志,一方面帮助日志微调,一方面及 ...

  8. 【大型网站技术实践】初级篇:借助Nginx搭建反向代理服务器

    一.反向代理:Web服务器的“经纪人” 1.1 反向代理初印象 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从 ...

  9. Windows平台分布式架构实践 - 负载均衡

    概述 最近.NET的世界开始闹腾了,微软官方终于加入到了对.NET跨平台的支持,并且在不久的将来,我们在VS里面写的代码可能就可以通过Mono直接在Linux和Mac上运行.那么大家(开发者和企业)为 ...

随机推荐

  1. 粗略了解struts2

    花了半天的时间再把struts2详细拟了一遍,之前用习惯了servlet加jsp,再看struts2的时候终于明白为什么大家都愿意学,以人类天生的惰性,要让他们愿意去学习一个新的东西,这东西一定可以让 ...

  2. Surprise团队第三周项目总结

    Surprise团队第二周项目总结 项目进展 这周我们小组的项目在上周的基础上进行了补充,主要注重在注册登录界面的实现,以及关于数据库的一些学习. 在设计注册登录界面时,每一块的地方控件都不一样,比如 ...

  3. POJ 1101 简单BFS+题意

    The Game 题意: Description One morning, you wake up and think: "I am such a good programmer. Why ...

  4. Linux Command Line 笔记(1)

    Yunduan CUI graphical user interfaces make easy tasks easy, while command line interfaces make diffi ...

  5. Scala笔记整理

    使用类型参数化数组(Array) 创建java.math.BigInteger实例: var big = new java .math.BigInteget("12345678") ...

  6. js数组的队栈操作

    <script> //一个数组 var testArray = [1,2,3,4,5]; //shift()方法,返回并移除数组中的第一个元素的值 testArray.shift();// ...

  7. mysql 求最小值/最大值

    计算所有人最低工资和最高工资,需分别用到min()和max()函数.(请注意,MIN和MAX函数会忽略NULL值) select min(sal) as min_sal , max(sal) as m ...

  8. UIScrollView在AutoLayout下的滚动问题

    使用Storyboard编写UI,设置支持AutoLayout. 在其中的一个场景上,添加一个UIScrollView,在对应的代码里增加 - (void)viewDidLoad { [super v ...

  9. 35 个 Java 代码性能优化总结

    前言 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用, ...

  10. Mysql与Oracle区别

    1.Oracle是大型数据库而Mysql是中小型数据库,Oracle市场占有率达40%,Mysql只有20%左右,同时Mysql是开源的而Oracle价格非常高. 2.Oracle支持大并发,大访问量 ...