1:线程池是什么:
线程池是并发编程必须要掌握的知识,在计算资源有限的情况下,线程的创建和销毁需要一定的性能,
而线程池原理很简单,类似于操作系统中的缓冲区的概念,它的流程:先启动若干数量的线程,并让这些线程都处于睡眠状态,当客户端有一个新请求时,就会唤醒线程池中的某一个睡眠线程,让它来处理客户端的这个请求,当处理完这个请求后,线程又处于睡眠状态。
线程池的优点:
第一:降低资源消耗,通过重复利用自己创建的线程降低线程创建和销毁造成的消耗。
第二: 提高响应速度,当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三: 提高线程的可管理性。线程是稀缺资源,如果无限的创建,不仅会消耗资源,还会较低系统的稳定性,使用线程池可以进行统一分配,调优和监控。
2:ThreadPoolExecutor是什么
ThreadPoolExecutor是java.util.concurrent包下的线程池,继承ExecutorService类.
《阿里巴巴Java开发手册》中强制线程池不允许使用 Executors 去创建,而是通过 new ThreadPoolExecutor 实例的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
Executors 返回线程池对象的弊端如下:
FixedThreadPool 和 SingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致OOM。
CachedThreadPool 和 ScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致OOM。
3:线程池状态
线程池有五种状态:RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED。
1. RUNNING:线程池一旦被创建,就处于 RUNNING 状态,任务数为 0,能够接收新任务,对已排队的任务进行处理。
2:SHUTDOWN: 不会接收新任务,但会处理阻塞队列剩余任务
3:STOP: 会中断正在执行的任务,并抛弃阻塞队列 任务
4:TIDYING: 任务全执行完毕,活动线程为 0 即将进入终结
5:TERMINATED: 终结状态
4:ThreadPoolExecutor的创建
1:构造方法
ThreadPoolExecutor的构造方法有多个,本文看构造参数最全的一个方法.
2:线程创建的步骤:
线程池中刚开始没有线程,当一个任务提交给线程池后,线程池会创建一个新线程来执行任务。
当线程数达到 corePoolSize 并没有线程空闲,这时再加入任务,新加的任务会被加入workQueue 队列排 队,直到有空闲的线程。
如果队列选择了有界队列,那么任务超过了队列大小时,会创建 maximumPoolSize - corePoolSize 数目的线 程来救急。
如果线程到达 maximumPoolSize 仍然有新任务这时会执行拒绝策略。
5:基于ThreadPoolExecutor实现的线程池
1:newFixedThreadPool
2:newCachedThreadPool
核心线程数是 0, 最大线程数是 Integer.MAX_VALUE,救急线程的空闲生存时间是 60s,意味着 全部都是救急线程(60s 后可以回收), 救急线程可以无限创建 ,队列采用了 SynchronousQueue 实现特点是,它没有容量.
整个线程池表现为线程数会根据任务量不断增长,没有上限,当任务执行完毕,空闲 1分钟后释放线 程。 适合任务数比较密集,但每个任务执行时间较短的情况
3:newSingleThreadExecutor
6:关闭线程池
1:shutdown
线程池状态变为 SHUTDOWN
不会接收新任务
但已提交任务会执行完
此方法不会阻塞调用线程的执行
2:shutdownNow
线程池状态变为 STOP
不会接收新任务
会将队列中的任务返回
并用 interrupt 的方式中断正在执行的任务
3:其他方法:
不在 RUNNING 状态的线程池,此方法就返回 true
boolean isShutdown();
线程池状态是否是 TERMINATED
boolean isTerminated();
调用 shutdown 后,由于调用线程并不会等待所有任务运行结束,因此如果它想在线程池 TERMINATED 后做些事情,可以利用此方法等待
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;