jdk的线程池实现-ThreadPoolExecutor
前言
一直以来对线程池的概念都挺模糊的,想不明白线程池要如何实现,今天难得周末,就开始查阅资料,研究了一下jdk中的线程池实现,终于解开了我长久以来的疑惑,本文参考文章来自网络,原文连接如下:
http://www.cnblogs.com/dolphin0520/p/3932921.html
参考连接针对jdk6,本文针对jdk8
疑惑
和线程池类似的有一个概念叫连接池,在数据库连接中使用的非常多,连接池比较好理解,一般来说就是一个连接建立完成之后不去关闭它,需要的时候就看获取这个连接的对象并给它的输入流写数据,并从输出流读取响应结果,但是在线程中,一旦某个线程的run方法运行结束之后,线程也就结束了,因此和连接池有很大的不同,这也给我留下了几个疑惑:
- 如何复用一个线程?
- 多个线程如何管理?
- 如何知道某个线程是目前正在运行还是在等待任务?
今天看过jdk中对线程池的实现,才真正明白,线程池和连接池是有很大不同的,使用上也完全不一样。
- 连接池是每次需要时候的时候,从池里取出一个连接给我们,我们再使用这个连接来交换数据,而线程池并不是在使用的时候从池里取出一个线程对象给我们使用,而是将我们的任务交给线程池,由线程池自己调度任务决定什么时候执行这个任务。
- 连接池的连接用完之后,会直接放到池内,等待下一个请求连接,而线程池的线程一旦运行完,线程也就结束了,因此不存在放回池内的操作。
- 一个连接池要持有一定数量的连接,只要保证持有这些未关闭的连接的对象即可,而线程池要持有一定数量的线程,必须保证持有的线程的run方法不会运行结束。
了解了线程池和连接池的区别之后,我们就可以知道,虽然名字很像,但是实际上这两者在原理和概念上是完全不一样的。
jdk1.5以后,新增了一个并发包java.concurrent
,这个包里就包含了线程池的实现,最核心的实现类是java.util.concurrent.ThreadPoolExecutor
。
实际上jdk从1.5到1.8,
java.util.concurrent.ThreadPoolExecutor
已经经过多次重构了,1.6和1.8在实现上已经有了很大的不同了,本文针对的是jdk8中的实现。
jdk的线程池实现
我们来看一下jdk中的线程池是如何实现的。
首先要先了解一下类结构,如下图:
类结构
最顶层的接口是java.util.concurrent.Executor
:
public interface Executor {
void execute(Runnable command);
}
只有一个接口,传入一个Runnable对象,称为指令,线程池就会帮你执行这个指令。
它的一级子接口是java.util.concurrent.ExecutorService
:
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws