前段时间自己研究了下线程池的实现原理,通过一些源码对比,发现其实核心的东西不难,于是抽丝剥茧,决定自己实现一个简单线程池,当自已实现了出一个线程池后。发现原来那么高大上的东西也可以这么简单。

先上原理图:为了更好的在手机上显示,我重新把图画了一遍

上代码之前,要先补充一下线程池构造的核心几个点

  1. 线程池里的核心线程数与最大线程数
  2. 线程池里真正工作的线程worker
  3. 线程池里用来存取任务的队列BlockingQueue
  4. 线程中的任务task

本例实现简化了一些,只实现了BlockingQueue存放任务,然后每个worker取任务并执行,下面看代码

首先定义一个线程池ThreadExcutor

class ThreadExcutor{

    //创建
private volatile boolean RUNNING = true; //所有任务都放队列中,让工作线程来消费
private static BlockingQueue<Runnable> queue = null; private final HashSet<Worker> workers = new HashSet<Worker>(); private final List<Thread> threadList = new ArrayList<Thread>(); //工作线程数
int poolSize = 0;
//核心线程数(创建了多少个工作线程)
int coreSize = 0; boolean shutdown = false; public ThreadExcutor(int poolSize){
this.poolSize = poolSize;
queue = new LinkedBlockingQueue<Runnable>(poolSize);
} public void exec(Runnable runnable) {
if (runnable == null) throw new NullPointerException();
if(coreSize < poolSize){
addThread(runnable);
}else{
//System.out.println("offer" + runnable.toString() + " " + queue.size());
try {
queue.put(runnable);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public void addThread(Runnable runnable){
coreSize ++;
Worker worker = new Worker(runnable);
workers.add(worker);
Thread t = new Thread(worker);
threadList.add(t);
try {
t.start();
}catch (Exception e){
e.printStackTrace();
} } public void shutdown() {
RUNNING = false;
if(!workers.isEmpty()){
for (Worker worker : workers){
worker.interruptIfIdle();
}
}
shutdown = true;
Thread.currentThread().interrupt();
}
//这里留个位置放内部类Worker
}

然后定义一个内部类Worker,这个内部类Worker是用来执行每个任务的,在创建线程池后,往线程里添加任务,每个任务都是由Worker一个一个来启动的。

    /**
* 工作线程
*/
class Worker implements Runnable{ public Worker(Runnable runnable){
queue.offer(runnable);
} @Override
public void run() {
while (true && RUNNING){
if(shutdown == true){
Thread.interrupted();
}
Runnable task = null;
try {
task = getTask();
task.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public Runnable getTask() throws InterruptedException {
return queue.take();
} public void interruptIfIdle() {
for (Thread thread :threadList) {
System.out.println(thread.getName() + " interrupt");
thread.interrupt();
}
}
}

首先注意的一点,这个Worker是个内部类,是在线程池内声明的。

exec方法

Worker怎么工作

这个工作线程实例化的时候就先加入一个任务到队列中,也就是说在实例化这个工作线程时,这个工作线程也是一个任务被加入到线程池中。然后就是run方法,这个run方法是线程调start方法生成的线程,而Worker调的run方法并没有生成新的线程。就是一个循环,一直在不停的从队列中取任务,然后执行。可以看到,取队列的方法是take(),这个方法意思如果队列为空了,取不到数据时就阻塞队列。

然后看shutdown()

你每天辛勤的劳动着,突然接收到上面的命令,说活暂时不要接了,先停下来,当你还没搞清楚状况时,接着你的领导又把你开除了,说公司要倒了,你先下岗吧,一会我也得下岗了。这就是shutdown做的事,shutdown必须是主线程才能停止工作线程。

shutdown方法并不是用线程那种强制停止的搞法,而是先用一个标识符告诉工作线程,不要再接任务了。然后通知工作线程,你可以interrupt()了,当所有的线程停止后记得要把主线程也停掉,这样,一个简单任务的线程池就完成了。

让我们来测试一下:

/**
* Created by wxwall on 2017/6/7.
*/
public class TheadBlockedQ {
public static void main(String[] args) throws InterruptedException {
ThreadExcutor excutor = new ThreadExcutor(3);
for (int i = 0; i < 10; i++) {
excutor.exec(new Runnable() {
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + " 在帮我干活");
}
});
}
excutor.shutdown();
}
}

输出结果为:

线程 Thread-0 在帮我干活
线程 Thread-2 在帮我干活
线程 Thread-1 在帮我干活
线程 Thread-0 在帮我干活
线程 Thread-2 在帮我干活
线程 Thread-2 在帮我干活
线程 Thread-1 在帮我干活
线程 Thread-0 在帮我干活
Thread-0 interrupt
Thread-1 interrupt
Thread-2 interrupt
Thread-0 interrupt
Thread-1 interrupt
Thread-2 interrupt
Thread-0 interrupt
Thread-1 interrupt
Thread-2 interrupt

这当然是最简单实现,JDK的实现比这强大的多,而且还具备当工作线程处理不过来时,可以产生新的线程来处理任务,这个数量不能超过原先定义的最大线程数,而在本例中都没实现这些功能。

我相信当想了解一个模块的功能时,如果一开始就了解其中最核心的点,然后向外慢慢扩展,那么学习这个模块时一定能省下不少时间,而且理解将很深刻。希望这个简单线程池实现能让你有所领悟,以更加简单的方式了解线程池,了解了线程池,对于其他池化技术,原理都是相通的。

最后我想说:我相信写好一篇文章能让大家理解不困难都是用了心的,您也点个赞支持支持。

java基础:简单实现线程池的更多相关文章

  1. JAVA基础拾遗-论线程池的线程粒度划分与深浅放置

    摘要:多线程任务处理对提高性能很有帮助,在Java中提供的线程池也方便了对多线程任务的实现.使用它很简单,而如果进行了不正确的使用,那么代码将陷入一团乱麻.因此如何正确地使用它,如以下分享,这个技能你 ...

  2. Java 基础 多线程和线程池基础

    一,多线程 1.1 多线程介绍 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是进程中的一个执行单元,负 ...

  3. Java一个简单的线程池实现

    线程池代码 import java.util.List; import java.util.Vector; public class ThreadPool  {     private static  ...

  4. Java多线程系列--“JUC线程池”04之 线程池原理(三)

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--“基础篇”01之 基 ...

  5. 简单C++线程池

    简单C++线程池 Java 中有一个很方便的 ThreadPoolExecutor,可以用做线程池.想找一下 C++ 的类似设施,尤其是能方便理解底层原理可上手的.网上找到的 demo,基本都是介绍的 ...

  6. Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  7. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  8. [转] 引用 Java自带的线程池ThreadPoolExecutor详细介绍说明和实例应用

    PS: Spring ThreadPoolTaskExecutor vs Java Executorservice cachedthreadpool 引用 [轰隆隆] 的 Java自带的线程池Thre ...

  9. Java并发编程:线程池的使用(转)

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  10. Java视频扩展知识 线程池的了解

     Java视频扩展知识   线程池的了解 1.简单介绍: Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用.为我们在开发中处理线程的 ...

随机推荐

  1. 优化UI控件 【译】

    翻译自:https://unity3d.com/cn/learn/tutorials/topics/best-practices/optimizing-ui-controls?playlist=300 ...

  2. Transform java future into completable future 【将 future 转成 completable future】

    Future is introduced in JDK 1.5 by Doug Lea to represent "the result of an asynchronous computa ...

  3. VirtulBox虚拟机搭建Linux Centos系统

    简要说明 该文章目的是基于搭建hadoop的前置文章,当然也可以搭建Linux的入门文章.那我再重复一下安装准备软件. 环境准备:http://pan.baidu.com/s/1dFrHyxV  密码 ...

  4. Spring boot 默认静态资源路径与手动配置访问路径

    在application.propertis中配置 ##端口号server.port=8081 ##默认前缀spring.mvc.view.prefix=/## 响应页面默认后缀spring.mvc. ...

  5. Android自定义评分控件:RatingStarView

    RatingStarView Android自定义的评分控件,类似ProgressBar那样的,使用星星图标(full.half.empty)作为progress标识的评分/打分控件. 效果图 图1: ...

  6. python object takes no parameters

    class Song(object): def __init__(self,lyrics): self.lyrics = lyrics def sing_me_a_song(self): for li ...

  7. OC中NSFileManager

    NSFileManager介绍 NSFileManager是用来管理文件系统的 它可以用来进行常见的文件\文件夹操作(拷贝.剪切.创建等) NSFileManager使用了单例模式singleton ...

  8. Archive for required library:xxxxx/spring-beans-3.2.4.RELEASE.jar in project XXXXX cannot be read or is not a valid ZIP file

    今天在导入maven项目的时候在problems视图中报错: Archive for required library:xxxxx/spring-beans-3.2.4.RELEASE.jar in ...

  9. 详解Google Chrome浏览器(操作篇)(下)

    开篇概述 由于最近忙于公司产品的架构与研发,已经三个多月没有写博客了,收到有些朋友的来信,问为什么不及时更新博客内容呢,他们说他们正期待着某些内容.对此,非常抱歉,那么我在此也给各位朋友一些承诺,从即 ...

  10. EntityFramework中出现DateTime2异常的完美解决办法

    今天在使用entityframework往数据库插入数据的时候,突然出现了一个数据类型转换异常的问题: System.Data.SqlClient.SqlException: 从 datetime2 ...