实现简单ThreadPool
在很多的应用场景,需要根据任务去创建线程去异步处理问题,不过不停的创建线程和销毁线程本身是一个非常耗时和消耗系统资源的事情,所以通常这种情况使用线程池来实现,常用的场景比如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的更多相关文章
- 简单看看ThreadPool的源码以及从中看出线程间传值的另一种方法
这几天太忙没时间写博客,今天回家就简单的看了下ThreadPool的源码,发现有一个好玩的东西,叫做”执行上下文“,拽名叫做:”ExecutionContext“. 一:ThreadPool的大概流程 ...
- ThreadPool.QueueUserWorkItem 简单示例,显示当前时间
1.线程池 添加方法 作为一个线程运行 class Program { static void Main(string[] args) { ThreadPool.QueueUserWorkItem( ...
- C# - 多线程 之 Process与Thread与ThreadPool
Process 进程类, // 提供对本地和远程进程的访问,启动/停止本地系统进程 public class Process : Component { public int Id { get; } ...
- C#多线程--线程池(ThreadPool)
先引入一下线程池的概念: 百度百科:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小,以默认的优先级运行, ...
- 【Quartz】配置最简单的集群
在许多情况,我们希望我们的定时任务是可靠的,不会因系统故障.机器宕机而导致某一笔定时任务不能按时运行.这种情况下,我们就需要为Quartz做个集群. 最简单的情况,有两台机器或两个应用,同时维护一批定 ...
- Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现
声明:本文为原创博文,转载请注明出处. Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程 ...
- C++11的简单线程池代码阅读
这是一个简单的C++11实现的线程池,代码很简单. 原理就是管理一个任务队列和一个工作线程队列. 工作线程不断的从任务队列取任务,然后执行.如果没有任务就等待新任务的到来.添加新任务的时候先添加到任务 ...
- Quartz定时任务简单实例
文章纲要: 初步搭建一个由Quartz为引擎集群的定时任务模块,功能为每隔30秒打印一条信息(Hello World!!!) 一.环境 Spring MVC Mevan Quartz 2.2.1 二. ...
- C#基础知识简单梳理
本文是转发博友的总结,方便自己以后随时温习: 1.值类型和引用类型 1.1堆和栈 简单的说值类型存放在堆栈上面,引用类型的数据存放在托管堆上面(它的引用地址却存放在堆栈上面)! 栈:它是一个内存数组, ...
随机推荐
- c# 关键字delegate、event(委托与事件)[MSDN原文摘录][1]
A delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++. ...
- oracle表分区【转】
摘要:在大量业务数据处理的项目中,可以考虑使用分区表来提高应用系统的性能并方便数据管理,本文详细介绍了分区表的使用. 在大型的企业应用或企业级的数据库应用中,要处理的数据量通常可以达到几十 ...
- mysql有回滚,php没有回滚的说法
mysql 事务表是有回滚的说法.当发生mysql层面的错误才会执行回滚
- AlarmManager手机闹钟简介
1.void set(int type , long triggerAtTime , PendingIntent operation ) : 设置在 triggerAtTime时间启动由operati ...
- 0302IT行业就业&软件工程之我所思和所想
阅读以下文章 http://www.thea.cn/news/terminal/9/9389.html http://www.shzhidao.cn/system/2015/09/22/0102610 ...
- webApi跨域
<system.webServer> <httpProtocol> <customHeaders> <add name="Access-Contro ...
- 电Call记录统计查询sql
DECLARE @startTime datetimeset @startTime='2016-07-12' SELECT * FROM (--坐席号/电话个数/通话总时长select zuoxi a ...
- bzoj 2428: [HAOI2006]均分数据
#include<cstdio> #include<iostream> #include<cstdlib> #include<ctime> #inclu ...
- 使用ASP.Net WebAPI构建REST服务(六)——Self-Host
Asp.Net WebAPI生成的是一个程序集,并不是独立的进程,因此,要运行的时候必须将其承载在相应的宿主上,一般比较常见的是IIS承载.很多时候,我们为了简化部署或者功能集成,需要将其承载到独立的 ...
- dedecms二级菜单实现
修改channelartlist.lib.php if($typeid==0 || $typeid=='top') { $tpsql = " reid=0 AND ispart<> ...