Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或者并发执行任务的程序都可以使用线程池。线程池能带来的好处:
当提交一个新的任务到线程池后,线程池的处理流程如下:
corePoolSize指定的数量maximumPoolSize值得注意的是,当线程池中的线程数大于等于corePoolSize,线程池也就完成了预热,之后再进来新任务,几乎所有的任务都是执行步骤3【大致流程可以理解为:优先让核心线程池的线程数达到充盈,借助新起的其他工作线程来辅助完成额外的任务】
流程示意图如下:


工作线程:线程池创建线程时,会将线程封装成工作线程 Worker,Worker 在执行完 任务后,还会循环获取工作队列里的任务来执行。
线程池中的线程执行任务分两种情况,如下:
execute()方法中创建一个线程时,会让这个线程执行当前任务BlockingQueue获取任务来执行使用ThreadPoolExecutor来创建一个线程池
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler
这几个相关的参数如下:
corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建 一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程, 等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的 prestartAllCoreThreads()方法,线程池会提前创建并启动所有基本线程maximumPoolSize:线程池允许创建的最大线程数【如果任务队列使用的是无界队列,该参数无效】keepAliveTime:线程保持活动时间。线程池的工作线程空闲后,保持存活的时间unit:线程保持活动时间的时间单位workQueue:用于保存等待执行的任务的阻塞队列(队列满时,阻塞插入操作;队列空时,阻塞获取操作)。可以选择以下几个阻塞队列:
ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按FIFO原则对元素进行排序LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按 FIFO 排序元 素,吞吐量通常要高于 ArrayBlockingQueueSynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个 线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于 Linked-BlockingQueuePriorityBlockingQueue:一个具有优先级的无限阻塞队列threadFactory:设置创建线程的工厂handler:饱和策略,当队列和线程池都满了,说明线程池处 于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是 AbortPolicy,表示无法处理新任务时抛出异常。在 JDK 1.5 中 Java 线程池框架提 供了以下 4 种策略
AbortPolicy:直接抛出异常CallerRunsPolicy:只用调用者所在线程来执行任务DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务DiscardPolicy:不处理,丢弃掉RejectedExecutionHandler接口自定义策略可以使用两个方法向线程池提交任务:
execute()submit()execute()
execute()用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功。它需要传入一个Runnable类的实例
public void execute(Runnable command) {
......
}
submit()
submit()用于提交需要返回值的任务,线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否成功,并且通过get()获取返回值,get()会阻塞当前线程直到任务完成。
Future<Object> future = executor.submit(harReturnValuetask);
try {
Object s = future.get();
} catch (InterruptedException e) {
// 处理中断异常
} catch (ExecutionException e) {
// 处理无法执行任务异常
} finally {
// 关闭线程池
executor.shutdown();
}
可以通过调用线程池的shutdown或shutdownNow来关闭线程池。它们的原理时遍历线程池中的工作线程,逐个调用线程的interrupt()来中断线程,所以无法响应中断的任务可能永远无法终止。
区别
shutdownNow:首先湘江线程池的状态设置为STOP,然后尝试停止所有正在执行或者暂停任务的线程,并返回等待执行任务的列表shutdown:将线程池的状态设置为SHUTWODN状态,然后中断所有没有正在执行的线程只要调用了这两个关闭方法中的任意一个,isShutdown 方法就会返回 true。当所有 的任务都已关闭后,才表示线程池关闭成功,这时调用 isTerminaed 方法会返回 true。至 于应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown方法来关闭线程池,如果任务不一定要执行完,则可以调用 shutdownNow 方 法