线程池提供了一种限制和管理资源(包括执行一个任务)。 使用线程池的好处:
Executor 框架是 Java5 之后引进的,在 Java 5 之后,通过 Executor 来启动线程比使用 Thread 的 start 方法更好。Executor 框架不仅包括了线程池的管理,还提供了线程工厂、队列以及拒绝策略等,Executor 框架让 并发编程变得更加简单。
在《阿里巴巴 Java 开发手册》“并发处理”这一章节,明确指出线程资源必须通过线程池提供
,不允许
在应用中自行显示创建线程
。另外《阿里巴巴 Java 开发手册》中强制线程池不允许使用 Executors 工具类去创建
,而是通过 ThreadPoolExecutor 构造函数的方式
,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
ThreadPoolExecutor 类中提供的四个构造方法。我们来看最长的那个,其余三个都是在这个构造方 法的基础上产生(其他几个构造方法说白点都是给定某些默认参数的构造方法比如默认制定拒绝策略是什么)
public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量 (重要参数)
int maximumPoolSize,//线程池的最大线程数 (重要参数)
long keepAliveTime,//当线程数大于核心线程数时,多余的空 闲线程存活的最长时间 (常见参数)
TimeUnit unit,//时间单位 (常见参数)
BlockingQueue<Runnable> workQueue,//任务队列,用来储 存等待执行任务的队列 (重要参数)
ThreadFactory threadFactory,//线程工厂,用来创建线程, 一般默认即可 (常见参数)
RejectedExecutionHandler handler) //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
{
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException(); //判断参数合法性
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException(); //判断参数合法性
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
ThreadPoolExecutor 3 个最重要的参数:
ThreadPoolExecutor 其他常见参数:
核心线程外的线程
不会立即销毁,而是会等待,直到等待的时间超过了 keepAliveTime 才会被回收销毁;ThreadPoolTaskExecutor 定义一些策略:
Runnable
接口不会返回结果或抛出检查异常,但是 Callable 接口可以。 工具类 Executors 可以实现 Runnable 对象和 Callable 对象之间的相互转换。execute()
方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;submit()
方法用于提交需要返回值的任务。线程池会返回一个 Future 类型的对象,通过这个 Future 对象可以判断任务是否执行成功,并且可以通过 Future 的 get() 方法来获取返回值, get() 方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit) 方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。shutdown()
:关闭线程池,线程池的状态变为 SHUTDOWN
。线程池不再接受新任务了,但是队列里的任务得执行完毕。shutdownNow()
:关闭线程池,线程的状态变为 STOP 。线程池会终止当前正在运行的任务,并停止处理排队的任务并返回正在等待执行的List。isShutDown
当调用 shutdown() 方法后返回为 true。isTerminated
当调用 shutdown() 方法后,并且所有提交的任务完成后返回为 true➢RUNNING :能接受新提交的任务, 并且也能处理阻塞队列中的任务
➢SHUTDOWN :不再接受新提交的任务,但可以处理存量任务
➢STOP :不再接受新提交的任务,也不处理存量任务
➢TIDYING :所有的任务都已终止
➢TERMINATED : terminated()方法执行完后进入该状态
Executors
创建不同的线程池满足不同场景的需求通过 Executor 框架的工具类 Executors 来实现,我们可以创建三种
类型的ThreadPoolExecutor:FixedThreadPool 、SingleThreadExecutor、 CachedThreadPool
。对应 Executors 工具类中的方法如下:
newFixedThreadPool(int pThreads)
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
2. newSingleThreadExecutor()
创建唯一的工作者线程来执行任务,如果线程异常结束,会有另一个线程取代它
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
//可以看出新创建的 `SingleThreadExecutor` 的 `corePoolSize` 和 `maximumPoolSize` 都被设置为 1.其他参数和 `FixedThreadPool` 相同。
3. newCachedThreadPool()
处理大量短时间工作任务的线程池,
(1) 试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;
(2) 如果线程闲置的时间超过阈值,则会被终止并移出缓存;
(3) 系统长时间闲置的时候,不会消耗什么资源
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
CachedThreadPool
的corePoolSize
被设置为空(0),maximumPoolSize
被设置为 Integer.MAX.VALUE,即它是无界的,这也就意味着如果主线程提交任务的速度高于 maximumPool
中线程处理任务的速度时,CachedThreadPool
会不断创建新的线程。极端情况下,这样会导致耗尽 cpu 和内存资源。
newSingleThreadScheduledExecutor()与newScheduledThreadPool(int corePoolSize)
定时或者周期性的工作调度,两者的区别在于单一工作线程还是多个线程,ScheduledThreadPoolExecutor
主要用来在给定的延迟后运行任务,或者定期执行任务。(了解即可)
ScheduledThreadPoolExecutor
使用的任务队列 DelayQueue
封装了一个 PriorityQueue
,PriorityQueue
会对队列中的任务进行排序,执行所需时间短的放在前面先被执行(ScheduledFutureTask
的 time
变量小的先执行),如果执行所需时间相同则先提交的任务将被先执行(ScheduledFutureTask
的 squenceNumber
变量小的先执行)。
newWorkStealingPool()
内部会构建ForkJoinPool ,利用working-stealing算法,并行地处理任务,不保证处理顺序
本文是通过学习“慕课网”视频,总结的学习笔记,也仅作为学习笔记,如有侵权请谅解,请勿转载。