为什么要用线程池
线程频繁地创建和销毁的开销巨大,通过线程池来对线程进行统一的管理,以达到线程重用的目的。
如何创建线程池
先贴一段简单的代码,通过Executors可以创建线程池,下面创建的是只有一个线程的线程池。
public class ThreadPoolTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor(); // 创建一个线程的线程池
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("当前执行线程名称:" + Thread.currentThread().getName());
}
});
}
}
---------------------------------------------------------------------------
输出:
当前执行线程名称:pool-1-thread-1
常见四种线程池创建方式
// 创建单个线程线程池
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
// 创建可缓存线程池
ExecutorService executorService2 = Executors.newCachedThreadPool();
// 创建指定核心线程数的线程池
ExecutorService executorService3 = Executors.newFixedThreadPool(5);
// 创建可定时调度并指定核心线程池的线程池
ExecutorService executorService4 = Executors.newScheduledThreadPool(5);
线程池的实现
随便点击创建线程池的方法,你会发现线程池内部是通过ThreadPoolExecutor类,顶层接口是Executor,接口方法execute(Runnable command)。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
ThreadPoolExecutor详解
ThreadPoolExecutor的继承体系
ThreadPoolExecutor有多个构造器,我们选个最多参数的来详细解析。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler){
}
corePoolSize:线程池核心线程数
maximumPoolSize:线程池最大线程数
keepAliveTime:线程池线程回收超时时长,默认是作用于非核心线程,如果ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,也会作用于核心线程
unit:线程回收超时时长的单位(纳秒、微秒、毫秒、秒、分、时、天),可通过枚举类TimeUnit设置
workQueue:缓冲任务队列,当corePoolSize< currentSize < maximumPoolSize时,任务会在队列中排队
threadFactory:为线程池提供创建新线程的线程工厂,使用默认实现DefaultThreadFactory即可。
handler:拒绝策略(线程数达到maximumPoolSize或者线程池关闭时),RejectedExecutionHandler有多个实现类,并且都是ThreadPoolExecutor的静态内部类,默认是AbortPolicy策略。
拒绝策略:
AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
DiscardPolicy:丢弃任务,但是不抛出异常。
DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
线程池执行流程
1,当currentPoolSize < corePoolSize时,直接启动核心线程执行任务。
2,当currentPoolSize >= corePoolSize,而且workQueue未满时,新的任务放到workQueue等待执行。
3,当workQueue已满,而且currentPoolSize < maximumPoolSize时,创建新的非核心线程执行任务。
4,当currentPoolSize >= maximumPoolSize,而且workQueue已满时,新的任务会直接触发拒绝策略,默认抛出RejectExecutionExpection异常。