Java线程池
Java线程池
利用Executors创建不同的线程池满足不同场景的需求
五种创建方式
为什么使用线程池
- 降低资源消耗
- 提高线程的可管理性
Executor框架
J.U.C(Java.util.concurrent)的三个Executor接口
- Executor:运行新任务的简单接口,将任务提交和任务执行细节解耦
- ExecutorService:具备管理执行器任务生命周期的方法,提交任务机制更完善
- ScheduledExecutorService:支持Future和定期执行任务
ThreadPoolExecutor
ThreadPoolExecutor的构造函数
参数:
- corePoolSize:核心线程数量
- MaximumPoolSize:线程不够用时能够创建的最大线程数
- workQueue:任务等待队列
- 常见队列类型:
- SynchronouseQueue:直接交接,内部没有容量
- LinkedBlokingQueue:无界队列,MaxPollSize参数等于没用了
- ArraryBlokingQueue:有界队列
- 常见队列类型:
- keepAliveTime:
- 线程池维护线程所允许的空闲时间,当线程池的线程数大于corePoolSize时,如果此时没有新的线程提交,多余线程不会立即被销毁,而是直到等待时间超过keepAliveTime
- threadFactory:
- 作用:创建新线程,默认使用Executors.defaultThreadFactory()
- 默认创建的线程拥有相同的优先级
- handler:线程池的饱和策略
- 如果阻塞队列满了并且没有空闲线程,此时如果继续提交任务,则需要采取一种策略处理该任务
- 线程池提供了四种策略:
- AbortPolicy:直接抛出异常,这是默认策略。
- DiscardPolicy:直接丢弃当前任务
- DiscardOldestPolicy:丢弃队列中最靠前(最老)的任务,并执行当前任务。
- CallerRunsPolicy:用调用者所在的线程来执行任务。
- 让主线程来执行也就没法再放任务进来,减轻负担
- 可以通过实现RejectedExecutionHandler接口自定义handler
新任务提交execute执行后的判断:
线程池的状态:
- RUNNING:能接受新提交的任务,也能处理阻塞队列的任务
- SHUTDOWN:不再接受新的提交任务,但是可以处理存量任务
- STOP:不再接受新的提交任务,也不处理存量任务
- TIDYING:所有任务都已终止,此后讲运行terminated()方法
- TERMINATED:terminated()方法执行完毕后进入该状态
工作线程的生命周期
线程池大小如何选定
- CPU密集型:线程数 = 核数或核数+1
- I/O密集型:线程数 = CPU核数*(1+平均等待时间/平均工作时间)
常见线程池
newFixedThreadPool
- 队列是LinkedBlokingQueue,无上限,容易OOM内存溢出
newSingleThreadExecutor
单独的线程,线程池里只有一个线程,其他和newFixedThreadPool基本一致
newCachedThreadPool
可缓存线程池
特点:无界线程池,具有自动回收多余线程的功能
队列是SynchronousQueue:直接提交任务,不存储
默认回收时间是60秒
newScheduledThreadPool
支持定时以及周期性执行任务的线程池
newWorkStealingPool
Fork/Join框架
Java7提供的用于并行执行任务的框架
- 把大任务分割成若干小任务并行执行,最终汇总每个小任务结果后得到大任务结果的框架
- 是ExecutorsService接口的具体实现
- 使用working-stealing算法:某个线程从其他队列里窃取任务来执行
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Alfred的小站!