有了ThreadPoolExecutor,还有Thread什么事
1.线程池是什么
线程池类似于数据库连接池,由于Thread 运行start()方法时,会创建线程。每次创建线程,会给系统增加额外的开销,所以线程池产生。每次执行线程代码时候,直接从线程池中获取线程执行代码。
2.线程池的作用
1.减少执行线程时,创建线程的额外开销(jvm中创建线程,需要创建虚拟机栈,本地方法栈等)。
过多的线程,会给jvm造成很大的压力。
2.销毁线程时,也会由于回收资源,消耗一定的性能。
3.线程池提供,拒绝策略,线程定时执行等功能,功能更加的完善。
3.Java中如何使用线程池
3.1 JUC中的线程池 ThreadPoolExecutor
jdk 1.5版本以后,出现了JUC(java.util.concurrent)工具包,
工具包中提供很多支持并发编程的工具类。ThreadPoolExecutor就是其中之一,目的是解决Thread 创建线程的缺陷。
3.2 从构造方法看起
ThreadPoolExecutor 存在多个构造方法的重载,这些构造方法的重载。传入的参数都是一致的只是,个数不同而已。我们挑一个参数最长的构造方法研究。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
-
corePoolSize 核心线程数
-
maximumPoolSize 最大线程数
-
keepAliveTime 线程存活的时间
-
workQueue 阻塞队列
-
threadFactory 线程工厂
-
handler 拒绝执行的策略
这几个参数的作用:用curSize代表当前线程中的线程数量,当新的任务需要执行时,这些参数有以下的作用: 1.curSize< corePoolSize 直接在线程池中创建新的线程,执行任务 2. corePoolSize<curSize<maximumPoolSize 如果线程中的阻塞队列中线程没有装满,直接将需要执行的任务,放入阻塞的队列中。 如果阻塞队列已经装满,直接创建新的线程执行任务。 3. curSize>maximumPoolSize 执行拒绝策略,即传入的handler中方法。
keepAliveTime 代表的是,超过核心线程数中线程如果空闲,在keepAliveTime时间之后将被销毁掉,线程池中只保留核心的线程数。
threadFactory 线程工厂可以对需要执行的线程,做相关的前置操作,如果打印线程的信息等等。
3.3 重点的api
线程池的api主要以下几个方面:
- 执行线程:execute(Runnable command)
- 关闭线程池:shutdown() 等待所有的线程执行结束关闭线程池 shutdownNow() ,立即关闭线程池。
- 获取线程池信息:getCorePoolSize()等
- 设置线程池的参数:setCorePoolSize()等
4.线程池的几种状态
- running 状态,可以执行需要执行的线程任务
- shutDown 状态 不在接受新的任务,保证阻塞队列中的任务执行完成。
- stop 状态 不在执行新的任务
- tidying状态 销毁线程,回收线程
- terminated 状态 完全的销毁线程池
5.Executor 创建线程池ExecutorServce
- newFixedThreadPool(int nThreads) 最大线程数为Integer.MaxValue 存在OOM 风险
- newCachedThreadPool() 存在oom 风险
- newSingleThreadScheduledExecutor(ThreadFactory threadFactory) 单线程定时执行
- newSingleThreadExecutor() 单线程执行
5.线程中出现的坑
- 手动创建线程池,避免OOM的风险
- 线程池使用完毕之后,记得关闭线程池。