以下内容转自http://ifeve.com/thread-pools/

线程池(Thread Pool)对于限制应用程序中同一时刻运行的线程数很有用。因为每启动一个新线程都会有相应的性能开销,每个线程都需要给栈分配一些内存等等。

我们可以把并发执行的任务传递给一个线程池,来替代为每个并发执行的任务都启动一个新的线程。只要池里有空闲的线程,任务就会分配给一个线程执行。在线程池的内部,任务被插入一个阻塞队列(Blocking Queue ),线程池里的线程会去取这个队列里的任务。当一个新任务插入队列时,一个空闲线程就会成功的从队列中取出任务并且执行它。

线程池经常应用在多线程服务器上。每个通过网络到达服务器的连接都被包装成一个任务并且传递给线程池。线程池的线程会并发的处理连接上的请求。以后会再深入有关Java实现多线程服务器的细节。

Java 5在java.util.concurrent包中自带了内置的线程池,所以你不用非得实现自己的线程池。你可以阅读我写的java.util.concurrent.ExecutorService的文章以了解更多有关内置线程池的知识。不过无论如何,知道一点关于线程池实现的知识总是有用的。

这里有一个简单的线程池实现:

public class ThreadPool {

    private BlockingQueue taskQueue = null;
private List<PoolThread> threads = new ArrayList<PoolThread>();
private boolean isStopped = false; public ThreadPool(int noOfThreads, int maxNoOfTasks){
taskQueue = new BlockingQueue(maxNoOfTasks); for(int i=0; i<noOfThreads; i++){
threads.add(new PoolThread(taskQueue));
}
for(PoolThread thread : threads){
thread.start();
}
} public synchronized void execute(Runnable task) throws Exception{
if(this.isStopped) throw
new IllegalStateException("ThreadPool is stopped"); this.taskQueue.enqueue(task);
} public synchronized void stop(){
this.isStopped = true;
for(PoolThread thread : threads){
thread.doStop();
}
} }
public class PoolThread extends Thread { private BlockingQueue taskQueue = null;
private boolean isStopped = false; public PoolThread(BlockingQueue queue){
taskQueue = queue;
} public void run(){
while(!isStopped()){
try{
Runnable runnable = (Runnable) taskQueue.dequeue();
runnable.run();
} catch(Exception e){
//log or otherwise report exception,
//but keep pool thread alive.
}
}
} public synchronized void doStop(){
isStopped = true;
this.interrupt(); //break pool thread out of dequeue() call.
} public synchronized boolean isStopped(){
return isStopped;
}
}

(校注:原文有编译错误,我修改了下)

public class PoolThread extends Thread {

  private BlockingQueue<Runnable> taskQueue = null;
private boolean isStopped = false; public PoolThread(BlockingQueue<Runnable> queue) {
taskQueue = queue;
} public void run() {
while (!isStopped()) {
try {
Runnable runnable =taskQueue.take();
runnable.run();
} catch(Exception e) {
// 写日志或者报告异常,
// 但保持线程池运行.
}
}
} public synchronized void toStop() {
isStopped = true;
this.interrupt(); // 打断池中线程的 dequeue() 调用.
} public synchronized boolean isStopped() {
return isStopped;
}
}

线程池的实现由两部分组成。类ThreadPool是线程池的公开接口,而类PoolThread用来实现执行任务的子线程。

为了执行一个任务,方法ThreadPool.execute(Runnable r)Runnable的实现作为调用参数。在内部,Runnable对象被放入阻塞队列 (Blocking Queue),等待着被子线程取出队列。

一个空闲的PoolThread线程会把Runnable对象从队列中取出并执行。你可以在PoolThread.run()方法里看到这些代码。执行完毕后,PoolThread进入循环并且尝试从队列中再取出一个任务,直到线程终止。

调用ThreadPool.stop()方法可以停止ThreadPool。在内部,调用stop先会标记isStopped成员变量(为 true)。然后,线程池的每一个子线程都调用PoolThread.stop()方法停止运行。注意,如果线程池的execute()stop()之后调用,execute()方法会抛出IllegalStateException异常。

子线程会在完成当前执行的任务后停止。注意PoolThread.stop()方法中调用了this.interrupt()。它确保阻塞在taskQueue.dequeue()里的wait()调用的线程能够跳出wait()调用(校对注:因为执行了中断interrupt,它能够打断这个调用),并且抛出一个InterruptedException异常离开dequeue()方法。这个异常在PoolThread.run()方法中被截获、报告,然后再检查isStopped变量。由于isStopped的值是true, 因此PoolThread.run()方法退出,子线程终止。

(校对注:看完觉得不过瘾?更详细的线程池文章参见Java线程池的分析和使用

26、Java并发性和多线程-线程池的更多相关文章

  1. 15、Java并发性和多线程-线程通讯

    以下内容转自http://ifeve.com/thread-signaling/: 线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 例如,线程B可以等待线程 ...

  2. 10、Java并发性和多线程-线程安全与不可变性

    以下内容转自http://ifeve.com/thread-safety-and-immutability/: 当多个线程同时访问同一个资源,并且其中的一个或者多个线程对这个资源进行了写操作,才会产生 ...

  3. 9、Java并发性和多线程-线程安全与共享资源

    以下内容转自http://ifeve.com/thread-safety/: 允许被多个线程同时执行的代码称作线程安全的代码.线程安全的代码不包含竞态条件.当多个线程同时更新共享资源时会引发竞态条件. ...

  4. java 并发性和多线程 -- 读感 (一 线程的基本概念部分)

    1.目录略览      线程的基本概念:介绍线程的优点,代价,并发编程的模型.如何创建运行java 线程.      线程间通讯的机制:竞态条件与临界区,线程安全和共享资源与不可变性.java内存模型 ...

  5. Java并发性和多线程

    Java并发性和多线程介绍   java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题, ...

  6. Java并发性和多线程介绍

    java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题,多开线程就好: 快速响应,异步式 ...

  7. Java 并发和多线程(一) Java并发性和多线程介绍[转]

    作者:Jakob Jenkov 译者:Simon-SZ  校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时 ...

  8. Java高级教程:Java并发性和多线程

    Java并发性和多线程: (中文,属于人工翻译,高质量):http://ifeve.com/java-concurrency-thread-directory/ (英文):http://tutoria ...

  9. Java并发(六)线程池监控

    目录 一.线程池监控参数 二.线程池监控类 三.注意事项 在上一篇博文中,我们介绍了线程池的基本原理和使用方法.了解了基本概念之后,我们可以使用 Executors 类创建线程池来执行大量的任务,使用 ...

随机推荐

  1. 二分图判定+点染色/并查集 BestCoder Round #48 ($) 1002 wyh2000 and pupil

    题目传送门 /* 二分图判定+点染色:因为有很多联通块,要对所有点二分图匹配,若不能,存在点是无法分配的,no 每一次二分图匹配时,将点多的集合加大最后第一个集合去 注意:n <= 1,no,两 ...

  2. 405 Convert a Number to Hexadecimal 数字转换为十六进制数

    给定一个整数,编写一个算法将这个数转换为十六进制数.对于负整数,我们通常使用 补码运算 方法.注意:    十六进制中所有字母(a-f)都必须是小写.    十六进制字符串中不能包含多余的前导零.如果 ...

  3. ios基础笔试题-集锦二

    前言 下文转载自:http://www.henishuo.com/objc-interview-two/ 1.即时聊天App不会采用的网络传输方式 A. UDP B. TCP C. HTTP D. F ...

  4. 面试中的一些小问题之html5和html4的区别?

    HTML5建立的一些新规则: 新特性应该基于HTML.CSS.DOM.JavaScript: 减少对外部插件的需求,如flash将会用video标签和audio标签代替: 更加优秀的错误处理: 更多取 ...

  5. C#.NET,技巧篇(DataGridView线程操作)

    这个系列的文章,主要是平时做C#.NET(Framework 3.5)开发的时候,积累的经验和技巧.我们平时总有这样的体会,遇到一个特别难解决的问题,网上寻它千百度也没能搜索到有用的信息.这时你肯定会 ...

  6. strong,weak, retain, assign的区别@property的参数

    strong,weak, retain, assign的区别@property的参数 先说经验 使用场合 copy:NSString,block, weak:UI控件,代理 strong:一般对象.自 ...

  7. Spartan6系列之芯片配置模式详解

    1.   配置概述 Spartan6系列FPGA通过把应用程序数据导入芯片内部存储器完成芯片的配置.Spart-6 FPGA可以自己从外部非易失性存储器导入编程数据,或者通过外界的微处理器.DSP等对 ...

  8. RabbitMQ调用

    添加 gradle依赖complie("com.rabbitmq:amqp-client:5.0.0") Hello, World Working Queues Publish/S ...

  9. 3星|林毅夫《战胜命运》:事实证明华盛顿共识是错误的,GIFF是穷国发展正道。

    本书是林毅夫与喀麦隆一位经济学家合著.基本的观点是:事实证明华盛顿共识是错误的,GIFF是穷国发展正道.GIFF的主要思想是政府找到对标国家,强力推行产业政策. 作为一个经济学外行,读后感觉关于华盛顿 ...

  10. Exception Information

    https://developer.apple.com/library/content/technotes/tn2004/tn2123.html Exception Information The t ...