我们在工程项目中,有时候既想拥有不错的并发体验,又想不要在应用中创建太多的线程(线程的创建还是有一定的开销的),这时就得用到jdk中的ThreadPoolExecutor类,相信java程序员对这个很面熟,但对于初学者来说,这里还是有一些细节需要注意一下。
首先们来看下ThreadPoolExecutor的构造函数,一共有4个重载的构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
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;
}
参数 threadFactory(可缺省)是用来指定线程创建的工厂类
参数 handler(可缺省)以下两种情况会触发:
- 当线程池已满负荷运行时(即正在执行的线程已经达到maximumPoolSize时),且workQueue也满的时候;
- 或者当调用者执行ThreadPoolExecutor#shutdown()来关闭线程池时
此时再通过ThreadPoolExecutor#execute()添加新的task时,就会触发,如果没有指定,execute()会抛出RejectedExecutionException异常(详见AbortPolicy类)
参数 corePoolSize 和 maximumPoolSize 用来控制线程池中常驻的线程数和最大池程数。
参数 keepAliveTime 和 unit(keepAliveTime的单位)用来控制当线程数超过corePoolSize时,超出corePoolSize且空闲的线程如果在keepAliveTime之内还未有新的task执行,则就会被释放。当然我们也可以通过ThreadPoolExecutor#allowCoreThreadTimeOut()来将keepAliveTime应用到corePoolSize之内的线程。
参数 workQueue 用来当线程已达到corePoolSize时,新添加的task会存入workQueue等待执行。
这里需要注意的是:
- 当线程数小于corePoolSize时,添加新的task时,就算有空闲的线程,ThreadPoolExecutor也会创建新的线程来执行
- 当正在运行的线程已达到corePoolSize时,添加新的task,就算当前线程数未达到maximumPoolSize,也会直接扔到workQueue等待执行。也就是说,当workQueue是可以无限扩展的队列时,maximumPoolSize,keepAliveTime和unit三个参数就会变得毫无意义
demo:
//创建一个常驻线程数为3,最大线程数为5,超出常驻线程数的空闲线程最大等待时间为1分钟,且最大等待的task数为1024的线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 1, TimeUnit.MINUTES,
new ArrayBlockingQueue<Runnable>(1024));
threadPoolExecutor.execute(new Runnable(){
@Override
public void run() {
System.out.println("test");
}
});