以下内容转自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. 递推DP Codeforces Round #260 (Div. 1) A. Boredom

    题目传送门 /* DP:从1到最大值,dp[i][1/0] 选或不选,递推更新最大值 */ #include <cstdio> #include <algorithm> #in ...

  2. 二分图最大匹配(匈牙利算法) UVA 10080 Gopher II

    题目传送门 /* 匈牙利算法:这题比UVA_670简单,注意是要被吃的鼠的最少个数,套模板 */ #include <cstdio> #include <algorithm> ...

  3. layer父页获取弹出层输入框里面的值

    主要是因为修改功能,原来页面填写数据如图 改为 其中点击填写明细弹出框 填写完毕后点击确认返回,同事这里因为她是存的多表,所以点击确认就直接保存数据了,改的这个功能原本保存是整体保存,我就不想改原来的 ...

  4. Spring.Net学习笔记(二)-数据访问器

    Spring对ADO.NET也提供了支持,依赖与程序集Spring.Data.dll IDbProvider IDbProvider定义了数据访问提供器的基础,配置如下 <?xml versio ...

  5. bash 博弈

    转载并修改自: http://www.cnblogs.com/wulangzhou/archive/2013/03/14/2959660.html 简单的取拿游戏一堆石子(或者其它的什么东西),下面是 ...

  6. 人人都能读懂的css3 3d小demo

    css3 3d案例总结 最近入坑 Web 动画,所以把自己的学习过程记录一下分享给大家.就把最近做的比较好的给大家分享下 1.旋转拼图 首先看下效果 代码主要由HTML和CSS3组成,应该说还是比较简 ...

  7. 深度优先搜索DFS和广度优先搜索BFS简单解析

    转自:https://www.cnblogs.com/FZfangzheng/p/8529132.html 深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每 ...

  8. key-value键值型数据库:Redis

    key-value键值型数据库:Redis redis Redis是in-memory型(内存型)的键值数据库,数据在磁盘上是持久的,键类型是字符串,值类型是字符串.字符串集合(Set).sorted ...

  9. canvas一周一练 -- canvas绘制奥运五环(1)

    运行效果: <!DOCTYPE html> <html> <head> </head> <body> <canvas id=" ...

  10. intellij idea console 乱码

    修改文件 位置:{用户目录}\{iedea对应版本}\{idea or idea64}.vmoptions 比如我要修改我的配置文件 C:\Users\kkblf\.IntelliJIdea2017. ...