在很多的应用场景,需要根据任务去创建线程去异步处理问题,不过不停的创建线程和销毁线程本身是一个非常耗时和消耗系统资源的事情,所以通常这种情况使用线程池来实现,常用的场景比如web容器对于web请求的处理,就是使用的线程池。线程池有几个关键性的元素:

  (1) 工作者线程,比如我们称为workers,负责需要处理的任务

  (2) 任务,比如我们称为Job,也就是需要处理的工作,通过线程池加入BlockingQueue中,然后由线程池的Job分配算法来分配给某一个worker(工作线程)

  (3) 线程池本身,包括线程池的初始化,以及Job的分配工作,复杂一些的包括动态的worker增减算法,在我们的简单示例里面只实现最基本的线程工作。

  实现的Java代码如下:

  

public class ThreadPool{
private static ThreadPool instance = new ThreadPool();
private BlockingQueue<Runnable> jobQueue;
private BlockingQueue<Worker> workers;
private int workerNum;
private ReentrantLock lock = new ReentrantLock(); final class Worker implements Runnable{
Runnable job = null;
public Worker() {
} @Override
public void run() {
// TODO Auto-generated method stub
try {
while ((job = jobQueue.take()) != null) {
job.run();
} } catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static ThreadPool getInstance() {
return instance;
} private ThreadPool() {
workers = new LinkedBlockingQueue<Worker>();
} public void init(int workerNum, BlockingQueue<Runnable> _jobQueue) {
this.workerNum = workerNum;
this.jobQueue = _jobQueue;
} public void execute(Runnable job) {
lock.lock();
try {
if (workers.size() < workerNum) {
Worker worker = new Worker();
Thread t = new Thread(worker);
t.start();
workers.add(worker);
} jobQueue.add(job);
} catch (Exception e) {
// TODO: handle exception
}
finally {
lock.unlock();
}
}
}
 从代码中可以看出ThreadPool代表线程池对象本身,用一个单例实现。其内部类Worker代表工作线程,用来实际处理Job,至于Job,在上面代码里面没有体现,不过jobQueue是一个容纳Runnable接口的队列,我们的Job只需要是一个实现Runnable接口的实例就可以了。BlockingQueue本身是线程安全的,所以Worker中是无需加锁的。不过对worker数量的判断和创建新的线程,需要加锁,防止创建了比设定更多的线程。
  测试代码:
package test;

import java.util.concurrent.LinkedBlockingQueue;

import pool.thread.*;

class TestJob implements Runnable {
int index = 0;
public TestJob(int _index) {
this.index = _index;
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("job start " + index + " thread id=" + Thread.currentThread().getId());
}
} public class TestThreadPool { public static void main(String[] args) {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
ThreadPool.getInstance().init(10, new LinkedBlockingQueue<Runnable>()); for (int i=0; i<1000; ++i) {
TestJob job = new TestJob(i+1);
ThreadPool.getInstance().execute(job);
} while (true) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} }

  从测试代码可以看出,TestJob这个Job只是简单的实现了Runnable接口。

  不过这个线程池只是为了实现线程池的核心思想,很多需要的功能没有实现,包括针对worker的动态删减,还有针对线程中所有线程的控制,比如中断线程执行等。不过核心的线程池思想还是可以通过上面的代码了解到的。

 

实现简单ThreadPool的更多相关文章

  1. 简单看看ThreadPool的源码以及从中看出线程间传值的另一种方法

    这几天太忙没时间写博客,今天回家就简单的看了下ThreadPool的源码,发现有一个好玩的东西,叫做”执行上下文“,拽名叫做:”ExecutionContext“. 一:ThreadPool的大概流程 ...

  2. ThreadPool.QueueUserWorkItem 简单示例,显示当前时间

    1.线程池  添加方法 作为一个线程运行 class Program { static void Main(string[] args) { ThreadPool.QueueUserWorkItem( ...

  3. C# - 多线程 之 Process与Thread与ThreadPool

    Process 进程类, // 提供对本地和远程进程的访问,启动/停止本地系统进程 public class Process : Component { public int Id { get; } ...

  4. C#多线程--线程池(ThreadPool)

    先引入一下线程池的概念: 百度百科:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小,以默认的优先级运行, ...

  5. 【Quartz】配置最简单的集群

    在许多情况,我们希望我们的定时任务是可靠的,不会因系统故障.机器宕机而导致某一笔定时任务不能按时运行.这种情况下,我们就需要为Quartz做个集群. 最简单的情况,有两台机器或两个应用,同时维护一批定 ...

  6. Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现

    声明:本文为原创博文,转载请注明出处. Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程 ...

  7. C++11的简单线程池代码阅读

    这是一个简单的C++11实现的线程池,代码很简单. 原理就是管理一个任务队列和一个工作线程队列. 工作线程不断的从任务队列取任务,然后执行.如果没有任务就等待新任务的到来.添加新任务的时候先添加到任务 ...

  8. Quartz定时任务简单实例

    文章纲要: 初步搭建一个由Quartz为引擎集群的定时任务模块,功能为每隔30秒打印一条信息(Hello World!!!) 一.环境 Spring MVC Mevan Quartz 2.2.1 二. ...

  9. C#基础知识简单梳理

    本文是转发博友的总结,方便自己以后随时温习: 1.值类型和引用类型 1.1堆和栈 简单的说值类型存放在堆栈上面,引用类型的数据存放在托管堆上面(它的引用地址却存放在堆栈上面)! 栈:它是一个内存数组, ...

随机推荐

  1. kafka技术要点

    转载:http://blog.csdn.net/caisini_vc/article/details/48007297 Kafka是分布式发布-订阅消息系统.它最初由LinkedIn公司开发,之后成为 ...

  2. "LC.exe" exited with code -1 错误

    当打开一个VS程序时出现"LC.exe" exited with code -1错误,解决方法是: 删除licenses.licx文件即可

  3. bzoj 2324: [ZJOI2011]营救皮卡丘

    #include<cstdio> #include<iostream> #include<cstring> #include<cmath> #inclu ...

  4. POJ 1850 Code 字符串 难度:1

    题意: 1 如果是严格升序的字母字符串,那么可以输出非0解码,否则不能译码输出0 2 字符串解码 遵循递增原则,其值为 到现在为止的所有按字母序小于该字符串的数量 + 1; #include < ...

  5. Redis系列-存储篇hash主要操作函数小结

    阳光透过玻璃,洒在身上,一杯暖茶在手,说不尽的安逸自得,让我有种想再写篇blog的冲动.上篇主要谈了string,这里谈谈hash吧!hash是一些列key value(field value)的映射 ...

  6. [开发笔记]-VS2012打开解决方案崩溃或点击项目崩溃

    下午在使用VS2012建立Service服务项目时,只要一切换到设计视图页面中,VS就崩溃重启,从网上找了一种方法来解决,测试可行.但导致该问题的原因未知. 解决方案: 步骤1:开始-->所有程 ...

  7. TClientDataSet 设计期 多次New 字段问题

    第一次New几个字段后,右键菜单CreateDataSet 后来需要再New几个字段. 右键菜单,先 ClearData(不这样,会报 打开的数据集不能执行 这个New字段的操作),然后在 字段编辑器 ...

  8. C++-new操作符

    1,new操作符实际上包含三部分:operator new分配内存和调用构造函数初始化刚刚分配的内存,类型转换刚刚的指针. string* ps = new string("lalalala ...

  9. SQL with PL/SQL

    DDL commands --> create user / table / view / sequence alter DML --> data manipulation languag ...

  10. Mac下SVN服务器环境的搭建和配置(除展示图片外,所有命令在Linux/Unix下适用)

    这几天领导没有安排工作,闲着没事就想把自己这两年做iOS开发时感觉知识有欠缺的地方想好好深入地补习一下,昨天和今天就计划好好学习下SVN和git的从创建和到原理,到命令,到界面的使用.一不小心被另一领 ...