简介
线程是一个程序员一定会涉及到的一个概念,但是线程的创建和切换都是代价比较大的。所以,我们有没有一个好的方案能做到线程的复用呢?这就涉及到一个概念——线程池。合理的使用线程池能够带来3个很明显的好处:
1.降低资源消耗:通过重用已经创建的线程来降低线程创建和销毁的消耗
2.提高响应速度:任务到达时不需要等待线程创建就可以立即执行。
3.提高线程的可管理性:线程池可以统一管理、分配、调优和监控。
java的线程池支持主要通过ThreadPoolExecutor来实现,我们使用的ExecutorService的各种线程池策略都是基于ThreadPoolExecutor实现的,所以ThreadPoolExecutor十分重要。要弄明白各种线程池策略,必须先弄明白ThreadPoolExecutor。
ThreadPoolExecutor的构造方法
ThreadPoolExecutor有四大构造方法,搞懂参数最多那个,其它的也就理解,具体看APi,
这里只讨论:
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
/**
* ThreadPoolExecutor有四大构造方法
* 重点看 七大构造参数的构造方法
* int corePoolSize,(核心线程池大小,要保持在池中的线程数)
*
* int maximumPoolSize,(线程池中允许的最大线程数)
*
* long keepAliveTime,(线程池中超过corePoolSize数目的空闲线程最大存活时间)
*
* TimeUnit unit,(时间单位)
*
* BlockingQueue<Runnable> workQueue,(阻塞任务队列)
*
* ThreadFactory threadFactory,(新建线程工厂)
*
* RejectedExecutionHandler handler (当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理)
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
想了解BlockingQueue workQueue:
想了解RejectedExecutionHandler handler:http://blog.csdn.net/Kincym/article/details/78318944
public class ThreadPoolExecutorTest {
private static final CountDownLatch countDownLatch = new CountDownLatch(3);
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor executorService = (ThreadPoolExecutor) buildPool();
// countDownLatch.await();
executorService.shutdown(); //任务执行完毕,关闭线程池。
executorService.awaitTermination(1,TimeUnit.HOURS);//等待结束,最多等待1个小时,线程池shutdown.
System.out.println("结束");
}
private static ExecutorService buildPool() {
/**
* 举例说明:何时启动最大线程数
* corePoolSize为1,maximumPoolSize为2,workQueue.size()为1
* I: 当启动2个线程时,corePoolSize启动一个,workQueue里面放一个,maximumPoolSize不启动
* II: 当启动三个线程时,corePoolSize启动一个,workQueue里面放一个,这时阻塞队列已经满了
* 这时maximumPoolSize启动了。
*/
ExecutorService executorService = new ThreadPoolExecutor(1, 2, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1),
r -> {
Thread t = new Thread(r);
return t;
}, new ThreadPoolExecutor.AbortPolicy());
System.out.println("线程池已创建");
executorService.execute(() -> sleepSeconds(5));
executorService.execute(() -> sleepSeconds(5));
executorService.execute(() -> sleepSeconds(5));
return executorService;
}
private static void sleepSeconds(int seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
System.out.println("***" + Thread.currentThread().getName() + "***");
// countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
shutdown():记得一定要关闭线程池。
awaitTermination(long timeout, TimeUnit unit):等待结束,最多等待指定时间。
注意shutdownNow():执行该方法,线程池的状态立刻变成STOP状态,并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务,当然,它会返回那些未执行的任务。它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,如果线程中有sleep 、wait、Condition、定时锁等应用, interrupt()方法是会中断当前的线程(慎用).
在JDKAPI中,更推荐使用Executors工厂类创建线程,前往:http://blog.csdn.net/Kincym/article/details/78306354