1.为什么要用线程池?
降低系统资源消耗
提高线程可控性
2.如何创建线程池?
JDK8中提供了5种创建线程池的方法
(1). newFixThreadPool
创建固定大小的线程池,可控制线程最大并发数,超过的线程会在队列中等待
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue
(2).(JDK8新增) newWorkStealingPool
会根据所需的并发数来动态创建和关闭线程,能够合理的使用CPU进行对任务进行并发操作,所以很适合使用在很耗时的任务上 public static ExecutorService newWorkStealingPool(int parallelism) { return new ForkJoinPool (parallelism, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); }
这里返回的是一个ForkJoinPool对象
public ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory, UncaughtExceptionHandler handler, boolean asyncMode) { this(checkParallelism(parallelism), checkFactory(factory), handler, asyncMode ? FIFO_QUEUE : LIFO_QUEUE, “ForkJoinPool-” + nextPoolId() + “-worker-”); checkPermission(); }
使用一个无限队列来保存需要执行的任务,可以传入线程的数量,不传入的话,默认使用当前计算机中可以使用的CPU数量,使用分治法来解决问题,使用fork()和join()来进行调用
(3).newCashedThreadPool
创建一个可缓存的线程池,可以灵活回收空闲线程,如果无法回收,则新建线程
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue
(4).newSingleThreadPoolExecutor
创建一个单线程的线程池
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue
(5).newScheduledThreadPool
创建一个定长线程池,支持定时以及周期性任务执行 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); }
3.源码结构(Executor框架结构)
从上往下依次是:
Executor
一个运行新任务的简单接口
ExecutorService
扩展了Executor接口,添加了一些用来管理执行器生命周期和任务生命周期的方法
AbstractExecutorService
对ExecutorService接口的抽象类实现
ThreadPoolExecutor
Java线程池的核心实现
4.线程池状态的转换模型
running:
线程池一旦被创建,就处于running状态,能够接收新任务,以及对已添加的任务进行处理
shutdown:
不能接收新任务,但能够处理已添加的任务
stop:
不接受新任务,不处理已添加的任务,并且会中断正在处理的任务
tidying:
当所有的任务已经终止,线程池就会变成tidying状态
terminated:
线程池彻底终止,就会变成terminated状态
最后修改于 2020-04-15

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。