简单来讲,创建线程池是为了提高当前应用的性能,减少因为系统创建线程所带来的性能消耗。
Jdk1.5中新增了java.util.concurrent.ThreadPoolExecutor线程池类,但是在创建时,强烈建议程序员使用较为方便的 Executors 工厂方法 Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)(固定大小线程池)和 Executors.newSingleThreadExecutor()(单个后台线程)。
现在我们分析下ThreadPoolExecutor是如何实现线程池的。
ThreadPoolExecutor类本身是用来管理,创建,销毁线程池中的线程的,其中管理所需要用到的主要数据结构包括:
runState:表示当前管理线程池线程的运行状态
workQueue:任务池缓冲队列
workers:存储线程池中当前工作的线程集合
corePoolSize:线程池的最小值或者是核心值
maximumPoolSize:线程池的最大值
poolSize:当前线程的数量
handler:用来处理请求拒绝的类
threadFactory:线程工厂
内部私有类Worker,专门处理任务的线程,主要数据包括
firstTask:初始化构造器,传进来的任务
thread:对线程的引用
ThreadPoolExecutor类的线程启动和管理。
所有任务都是通过execute方法放入事先Runnable接口的任务。
当线程管理池启动线程后调用worker的run方法
看看ThreadPoolExecutor线程池是的管理线程池的
1.当poolSize <=corePoolSize时,且线程池的状态为RUNNING时,产生新的worker线程处理任务。
2.当poolSize =corePoolSize时,将task放入工作队列。
3.当poolSize < maximumPoolSize时,并且工作队列满时,才会生成的新的线程。
4.当poolSize = maximumPoolSizee时,并且工作队列满时,使用拒绝策略拒绝请求。
5.当队列中没有任务的时候,且线程池中存在空闲的线程(根据构建线程池传入的keepAliveTime作为到
BlockingQueue获取任务的超时时间),这样线程池会收缩空闲线程到corePoolSize。
启动线程池看完了,我们再看看终止线程池是如何操作的。
首先看入口
shutdown(); 按过去执行已提交任务的顺序发起一个有序的关闭,但是不接受新任务。
shutdownNow();尝试停止所有的活动执行任务、暂停等待任务的处理,并返回等待执行的任务列表。
参考文章
http://www.blogjava.net/feuyeux/archive/2010/12/04/339799.html
http://blog.youkuaiyun.com/booboo2006/archive/2008/08/05/2770897.aspx
http://jclown.iteye.com/blog/769608
http://www.ibm.com/developerworks/cn/java/l-threadPool/
Jdk1.5中新增了java.util.concurrent.ThreadPoolExecutor线程池类,但是在创建时,强烈建议程序员使用较为方便的 Executors 工厂方法 Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)(固定大小线程池)和 Executors.newSingleThreadExecutor()(单个后台线程)。
现在我们分析下ThreadPoolExecutor是如何实现线程池的。
ThreadPoolExecutor类本身是用来管理,创建,销毁线程池中的线程的,其中管理所需要用到的主要数据结构包括:
runState:表示当前管理线程池线程的运行状态
workQueue:任务池缓冲队列
workers:存储线程池中当前工作的线程集合
corePoolSize:线程池的最小值或者是核心值
maximumPoolSize:线程池的最大值
poolSize:当前线程的数量
handler:用来处理请求拒绝的类
threadFactory:线程工厂
内部私有类Worker,专门处理任务的线程,主要数据包括
firstTask:初始化构造器,传进来的任务
thread:对线程的引用
ThreadPoolExecutor类的线程启动和管理。
所有任务都是通过execute方法放入事先Runnable接口的任务。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
//addIfUnderCorePoolSize(command)方法主要是当poolSize < corePoolSize时,在线程池中创建线程
//当创建成功时候返回true,否则false
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
}
else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
}
}
addIfUnderCorePoolSize(command)
if (poolSize < corePoolSize && runState == RUNNING)
//创建新的线程
t = addThread(firstTask);
//启动线程
t.start();
private Thread addThread(Runnable firstTask) {
//通过构造器,把第一个任务交给worker线程处理
Worker w = new Worker(firstTask);
//通过线程工厂包装worker线程,设置对应的属性
//newThread(w)方法如下
// Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(), 0);
// if (t.isDaemon())
// t.setDaemon(false);
// if (t.getPriority() != Thread.NORM_PRIORITY)
// t.setPriority(Thread.NORM_PRIORITY);
Thread t = threadFactory.newThread(w);
if (t != null) {
//实际上就是用Runnable生产了一个工人,而线程工厂使用了工人生产出一个线程,
//再用工人内部的一个属性指向这个线程。
//其实这里所做的是让t和w都有互相的引用,以便今后操作。
w.thread = t;
workers.add(w);
int nt = ++poolSize;
if (nt > largestPoolSize)
largestPoolSize = nt;
}
return t;
}
当线程管理池启动线程后调用worker的run方法
public void run() {
try {
Runnable task = firstTask;
firstTask = null;
//当首任务不为空执行任务,或者能从workQueue中获取任务则执行
//一直到没有任务执行位置
while (task != null || (task = getTask()) != null) {
//真正执行任务的方法
runTask(task);
task = null;
}
} finally {
workerDone(this);
}
}
//getTask()为线程管理池方法
Runnable getTask() {
for (;;) {
try {
int state = runState;
//当runState大于SHUTDOWN时,无论任务队列是否有任务都不执行
if (state > SHUTDOWN)
return null;
Runnable r;
//当线程池状态为SHUTDOWN的时候,继续把队列中的任务取出执行完
if (state == SHUTDOWN) // Help drain queue
r = workQueue.poll();
//如果超过核心池,说明任务已经非常多了,工人线程等待一段时间还没有得到一个任务,
//就马上返回不再等下去。
else if (poolSize > corePoolSize || allowCoreThreadTimeOut)
r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
else
//正常情况,说明线程不多,用take,
//即使队列被锁住了,无论如何也要等到一个任务
r = workQueue.take();
if (r != null)
return r;
//如果取出的任务为null,判断工作线程是否可以退出
//runState >= STOP ||workQueue.isEmpty() ||
//(allowCoreThreadTimeOut && poolSize > Math.max(1, corePoolSize));
//以上任意一种情况成立,工作线程都退出
if (workerCanExit()) {
if (runState >= SHUTDOWN) // Wake up others
interruptIdleWorkers();
return null;
}
// Else retry
} catch (InterruptedException ie) {
// On interruption, re-check runState
}
}
}
runTask(task);
beforeExecute(thread, task);
//真正执行的任务
task.run();
afterExecute(task, null);
void workerDone(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
//将工作线程移除出工作线程集合
//使之变为非工作线程,
//注:并没有将线程移除线程池,只是相当于标记线程是空闲还是繁忙
workers.remove(w);
if (--poolSize == 0)
tryTerminate();
} finally {
mainLock.unlock();
}
}
看看ThreadPoolExecutor线程池是的管理线程池的
1.当poolSize <=corePoolSize时,且线程池的状态为RUNNING时,产生新的worker线程处理任务。
2.当poolSize =corePoolSize时,将task放入工作队列。
3.当poolSize < maximumPoolSize时,并且工作队列满时,才会生成的新的线程。
4.当poolSize = maximumPoolSizee时,并且工作队列满时,使用拒绝策略拒绝请求。
5.当队列中没有任务的时候,且线程池中存在空闲的线程(根据构建线程池传入的keepAliveTime作为到
BlockingQueue获取任务的超时时间),这样线程池会收缩空闲线程到corePoolSize。
启动线程池看完了,我们再看看终止线程池是如何操作的。
首先看入口
shutdown(); 按过去执行已提交任务的顺序发起一个有序的关闭,但是不接受新任务。
shutdownNow();尝试停止所有的活动执行任务、暂停等待任务的处理,并返回等待执行的任务列表。
//shutdown()调用的
for (Worker w : workers) {
//终止每个worker
w.interruptIfIdle();
}
void interruptIfIdle() {
final ReentrantLock runLock = this.runLock;
if (runLock.tryLock()) {
try {
if (thread != Thread.currentThread())
thread.interrupt();
} finally {
runLock.unlock();
}
}
}
参考文章
http://www.blogjava.net/feuyeux/archive/2010/12/04/339799.html
http://blog.youkuaiyun.com/booboo2006/archive/2008/08/05/2770897.aspx
http://jclown.iteye.com/blog/769608
http://www.ibm.com/developerworks/cn/java/l-threadPool/