在很多的应用场景,需要根据任务去创建线程去异步处理问题,不过不停的创建线程和销毁线程本身是一个非常耗时和消耗系统资源的事情,所以通常这种情况使用线程池来实现,常用的场景比如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. springmvc 配置直接访问页面

    <mvc:view-controller path="/" view-name="/home"/> 在mvc中配置,访问路径就可以了

  2. 用Masonry实现键盘的收回和弹出

    首先说几点:我一般将数值类型的约束用mas_equalTo,而相对于某个控件,或者某个控件的某个约束,我会使用equalTo,如:make.size.mas_equalTo(CGSizeMake(10 ...

  3. java面向对象编程—— 第三章 程序流程控制

    3.1流程控制 三种基本技术可以改变程序的控制流程: ①   调用方法:调用方法将导致控制流程离开当前方法,转移到被调用的方法: ②   选择:java中有两种做出选择的机制:if/else语句和sw ...

  4. POJ 2965 The Pilots Brothers' refrigerator 暴力 难度:1

    The Pilots Brothers' refrigerator Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16868 ...

  5. getBoundingClientRect() 来获取页面元素的位置

    getBoundingClientRect() 来获取页面元素的位置   document.documentElement.getBoundingClientRect 下面这是MSDN的解释: Syn ...

  6. MATLAB图像处理函数汇总(一)

    1.applylut功能: 在二进制图像中利用lookup表进行边沿操作.语法:A = applylut(BW,lut)举例lut = makelut('sum(x(:)) == 4',2);BW1 ...

  7. [安卓][转]Android eclipse中程序调试

    一:断点调试 用eclipse开发android程序的时,跟VS一样是可以断点单步调试的.步骤如下.1 设置断点:在编码窗体的左边框上用鼠标双击,或者右键点击菜单,选择 Toggle Breakpoi ...

  8. VMWare Workstation 10.0 Preview CN

    What's New in the VMware Workstation Technology Preview July 2013 The VMware Workstation team is exc ...

  9. 大嫂的HTML

      <html>   <head>   <style type="text/css">   *{ margin: 0; padding: 0; ...

  10. PHPSESSID的cookie

    如果PHP脚本中有: 1 session_start(); 则说明使用了SESSION. SESSION是一种机制,可以在服务器端跨文件暂时保存数据或传递数据,常用于购物车等方面. SESSION只在 ...