JDK本身已经提供了完整的线程池实现,因此在使用JAVA中使用线程池是很轻松方便的。
查看线程池的构造器
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
其中 corePoolSize表示默认的线程数量,maximumPoolSize 表示最大的线程数量,workQueue 代表执行任务的等待队列。keepAliveTime表示线程的保持时间,如果线程数大于corePoolSize时,如果线程在keepAliveTime时间内没有获取到执行任务,就将线程销毁掉,保持线程池中只有corePoolSize个线程。 threadFactory线程工厂,handler,当线程池满时,采用的处理策略。
查看
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
可以发现线程池的使用会经历一下几个阶段。
1, 线程池刚启动,此时线程池中没有线程。
2,一个执行任务添加到线程池中。线程池发现当前线程数小于corePoolSize,新加一个worker线程,执行任务。
3,继续向线程池中添加执行任务,如果线程池的线程数量已经等于corePoolSize,将执行任务添加到队列中,如果加入队列失败,将增加一个worker线程执行任务。
4, 如果步骤3中,worker线程数量已经等于maximumPoolSize,执行handler接口定义的方法,代表线程池已满。
上面的过程会有一个很蛋疼的问题,就是只有线程队列满了之后,才会启用新的线程。加入初始设定corePoolSize=1,maximumPoolSize=150,queue采用默认长度Integer.MAX_VALUE。那么执行结果会是怎么样呢,那就是在排队任务必须等于Integer.MAX_VALUE时,才会启动第二个线程,直到150个线程。可以认为,只开通一个售票窗口,直到排队的人塞满之后,才会开动第二个窗口。
换一个思路,能不能发现有人在排队的时候,就将所有的窗口打开,这样,大多数任务都不用长时间排队的问题。按照这种思路,实现一种动态分配线程数的策略,使有任务排队时实际线程数在corePoolSize ~ maximumPoolSize 之间移动。
实现代码如下:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author liaokucheng@ftown.com
* @date 2016年11月10日
*
*/
public class DynamicThreadPool extends ThreadPoolExecutor {
private volatile int corePoolSize;
private volatile int maxPoolSize;
private volatile int poolSize;
/**
* @param corePoolSize
* @param maximumPoolSize
* @param keepAliveTime
* @param unit
* @param workQueue
*/
public DynamicThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);
this.corePoolSize = corePoolSize;
this.maxPoolSize = maximumPoolSize;
this.poolSize = corePoolSize;
}
/**
* 改变核心线程数
*/
private void changeCoorePoolSize(int i) {
if (i > 0) {// 增加
if (poolSize < maxPoolSize) {
poolSize += i;
this.setCorePoolSize(poolSize < maxPoolSize ? poolSize : maxPoolSize);
startMonitor();// 增加线程数时,需要启动监控线程,由监控线程来控制空闲时,线程数的减少
}
} else {// 减少,减少时,不需要启动监控线程
if (poolSize > corePoolSize) {
poolSize += i;
this.setCorePoolSize(poolSize > corePoolSize ? poolSize : corePoolSize);
}
}
}
/**
* 动态增长
*/
private void dynamicChange() {
if (poolSize < maxPoolSize) {
if (this.getTaskCount() - this.getCompletedTaskCount() > poolSize) {// 任务数量超过最小线程数量,有任务增正在排队
changeCoorePoolSize(1);
}
}
}
@Override
public void execute(Runnable command) {
dynamicChange();
super.execute(command);
}
/**
* 监控线程,使用监控线程来控制最小线程数
*
* @author liaokucheng@ftown.com
* @date 2016年11月10日
*
*/
protected class MonitorThread extends Thread {
/**
* 1分钟
*/
private volatile int sleepTime = 60000;
public void run() {
while (true) {
//如果线程池已经被关闭,那么结束监控线程线程
if (isShutdown()) {
return;
}
execute();
}
}
void execute() {
try {
Thread.sleep(sleepTime);
if (poolSize > corePoolSize) {
//未完成的任务数小于线程数,则认为线程有空闲,应该减少线程数
if (getTaskCount() - getCompletedTaskCount() < poolSize) {
changeCoorePoolSize(-1);
return;
}
}
} catch (InterruptedException e) {
// TODO
}
}
}
private volatile MonitorThread monitor;
/**
* 启动监控线程,使用double-check来保证监控线程的单例
*/
private void startMonitor() {
if (null == monitor) {
synchronized (this) {
if (null == monitor) {
monitor = new MonitorThread();
monitor.setDaemon(true);
monitor.start();
}
}
}
}
}
添加任务时,判断未执行完成的任务是否大于当前线程数,如果大于,增加corePoolSize,同时,启动一个监控线程,监控线程用于线程池空闲时,缩小corePoolSize的值