26、Java并发性和多线程-线程池
以下内容转自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并发性和多线程-线程池的更多相关文章
- 15、Java并发性和多线程-线程通讯
以下内容转自http://ifeve.com/thread-signaling/: 线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 例如,线程B可以等待线程 ...
- 10、Java并发性和多线程-线程安全与不可变性
以下内容转自http://ifeve.com/thread-safety-and-immutability/: 当多个线程同时访问同一个资源,并且其中的一个或者多个线程对这个资源进行了写操作,才会产生 ...
- 9、Java并发性和多线程-线程安全与共享资源
以下内容转自http://ifeve.com/thread-safety/: 允许被多个线程同时执行的代码称作线程安全的代码.线程安全的代码不包含竞态条件.当多个线程同时更新共享资源时会引发竞态条件. ...
- java 并发性和多线程 -- 读感 (一 线程的基本概念部分)
1.目录略览 线程的基本概念:介绍线程的优点,代价,并发编程的模型.如何创建运行java 线程. 线程间通讯的机制:竞态条件与临界区,线程安全和共享资源与不可变性.java内存模型 ...
- Java并发性和多线程
Java并发性和多线程介绍 java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题, ...
- Java并发性和多线程介绍
java并发性和多线程介绍: 单个程序内运行多个线程,多任务并发运行 多线程优点: 高效运行,多组件并行.读->操作->写: 程序设计的简单性,遇到多问题,多开线程就好: 快速响应,异步式 ...
- Java 并发和多线程(一) Java并发性和多线程介绍[转]
作者:Jakob Jenkov 译者:Simon-SZ 校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时 ...
- Java高级教程:Java并发性和多线程
Java并发性和多线程: (中文,属于人工翻译,高质量):http://ifeve.com/java-concurrency-thread-directory/ (英文):http://tutoria ...
- Java并发(六)线程池监控
目录 一.线程池监控参数 二.线程池监控类 三.注意事项 在上一篇博文中,我们介绍了线程池的基本原理和使用方法.了解了基本概念之后,我们可以使用 Executors 类创建线程池来执行大量的任务,使用 ...
随机推荐
- Modbus消息帧
两种传输模式中(ASCII和RTU),传输设备以将Modbus消息转为有起点和终点的帧,这就允许接收的设备在消息起始处开始工作,读地址分配信息,判断哪一个设备被选中(广播方式则传给所以设备),判知何时 ...
- P1334 瑞瑞的木板
题目描述 瑞瑞想要亲自修复在他的一个小牧场周围的围栏.他测量栅栏并发现他需要N(1≤N≤20,000)根木板,每根的长度为整数Li(1≤Li≤50,000).于是,他神奇地买了一根足够长的木板,长度为 ...
- 2017-12-04HTML table布局
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- Unity笔记(3)自学第三天
学习记录: 脚本使用:
- JVM GC调优一则–增大Eden Space提高性能
缘起 线上有Tomcat升级到7.0.52版,然后有应用的JVM FullGC变频繁,在高峰期socket连接数,Cpu使用率都暴增. 思路 思路是Tomcat本身的代码应该是没有问题的,有问题的可能 ...
- The user specified as a definer ('root'@'%') does not exist 解决方法
mysql> grant all privileges on *.* to root@"%" identified by "."; Query OK, r ...
- MySQL的基本概念与操作
数据库的基本概念什么是数据库?用于存储和管理数据的仓库.数据库的特点:持久化存储数据的.其实数据库就是一个文件系统方便存储和管理数据使用了统一的方式操作数据库 – SQL数据库的分类:数据库根据存储采 ...
- TestNG套件测试(一)
测试套件是用于测试软件程序的行为或一组行为的测试用例集合. 在TestNG中,我们无法在测试源代码中定义一个套件,但它可以由一个XML文件表示,可以灵活配置要运行的测试. 套件用<suite&g ...
- nginx代理标准配置
#nginx开启的进程数worker_processes 4; #4核CPU #定义全局错误日志定义类型,[debug|info|notice|warn|crit]error_log ...
- 初遇Java
什么是JVM?JVM是java虚拟机(JVM Java Virtual Machine),java程序需要运行在虚拟机上,不同平台有自己的虚拟机,因此java语言可以跨平台. 什么是JRE?包括Jav ...