前言

并发(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. html的基础标签

    完整的网页由html嵌套 head.body构成 实例: <!DOCTYPE html><html lang="en"> <head> < ...

  2. sqlserver字段类型

    bit    整型 bit数据类型是整型,其值只能是0.1或空值.这种数据类型用于存储只有两种可能值的数据,如Yes 或No.True 或False .On 或Off. 注意:很省空间的一种数据类型, ...

  3. jsp xml servlet

    什么都懂一点,什么都不精通!!

  4. 用js判断页面刷新或关闭的方法

    Onunload,onbeforeunload都是在刷新或关闭时调用,可以在<script>脚本中通过window.onunload来指定或者在<body>里指定.区别在于on ...

  5. [THINKING IN JAVA]复用类

    7 复用类 7.1 组合 即在一个类中使用另一个类作为成员变量,这是复用了现有程序代码的功能,而非形式. 7.2 继承 关键字:extends,这种复用是形式的复用,是一种可扩展和限制的复用: 复用: ...

  6. js中event.target

    event.srcElement从字面上可以看出来有以下关键字:事件,源     他的意思就是:当前事件的源, 我们可以调用他的各种属性 就像:document.getElementById(&quo ...

  7. python logging模块详解[转]

    一.简单将日志打印到屏幕: import logging logging.debug('debug message') logging.info('info message') logging.war ...

  8. asp.net 自定义控件 嵌入资源文件 备忘

    要想在自定义用户控件中嵌入资源,从以下几个步骤入手: 1.在AssemblyInfo.cs中注册资源,文件夹层级用点隔开.例如: [assembly: System.Web.UI.WebResourc ...

  9. Android应用内存泄漏的定位、分析与解决策略

    什么是内存泄漏 对于不同的语言平台来说,进行标记回收内存的算法是不一样的,像 Android(Java)则采用 GC-Root 的标记回收算法.下面这张图就展示了 Android 内存的回收管理策略( ...

  10. ETL利器Kettle实战应用解析系列二 【应用场景和实战DEMO下载】

    本文主要阅读目录如下: 1.应用场景 2.DEMO实战 3.DEMO下载 1.应用场景 这里简单概括一下几种具体的应用场景,按网络环境划分主要包括: 表视图模式:这种情况我们经常遇到,就是在同一网络环 ...