线程池
线程池参数
- corePoolSize:核心线程数大小
- maximumPoolSize:线程池最大线程数
- keepAliveTime:线程池中非核心线程空闲的存活时间(与是否超过核心线程数有关)
- unit:线程存活时间单位
- workQueue:存放任务的阻塞队列
- handler:饱和策略
- threadFactory:设置创建线程的工厂,一般默认
核心线程和最大线程数的区别?
任务提交至后,判断核心线程数是否已满?未满的话,创建一个线程。否则进入阻塞队列workQueue。此时无关最大线程数。
提交的任务后,阻塞队列已满,看是否超过最大线程数,没有的话,创建线程执行。
若超过最大线程数,则执行饱和策略handler。
执行完后,存活时间有keepAliveTime。
拒绝策略handler
4种:
- Abort——直接抛出异常RejectExecutionException,阻止系统正常工作
- CallerRuns——直接在调用者线程中运行
- DiscardOldest:丢弃即将执行的任务
- Discard:直接丢弃
默认:AbortPolicy
阻塞队列
- ArrayBlockingQueue——有界
- PriorityBlockingQueue —— 无界
- LinkedListBlockingQueue——可看做无界,默认大小为Integer.MAX_VALUE
- DelayBlockingQueue——基于PriorityBlockingQueue
线程池类型
- 固定大小的线程池
- 计划任务线程池
- 单线程线程池
- 可缓存线程池
1、固定大小的线程池
package com.concurrency; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolDemo { public static class MyTask implements Runnable{ @Override public void run() { System.out.println(System.currentTimeMillis() + "Thread ID" + Thread.currentThread().getId() ); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { MyTask myTask = new MyTask(); ExecutorService service = Executors.newFixedThreadPool(5); for(int i = 0;i < 10;i++){ service.submit(myTask); } } }
调用new FixedThreadPool(),会创建一个具有固定数目线程的线程池。每次提交一个任务,就创建一个线程,知道达到线程池的最大大小(和设置的一样)。
若其中某个线程执行异常结束,则线程池会补充一个新线程。
使用哪种队列?
无界的LinedBlockingQueue。
使用无界队列的线程池会导致内存占用飙升吗?
会。假如线程任务执行时间过长,则会导致队列的任务越积越多,最终导致OOM Error。
适合场景?
适合确定cpu被长时间占用的情况。
工作机制?
- 提交任务时,线程池创建一个线程执行任务。
- 到达核心线程数目时,新的任务添加至LinkedBlokingQueue
- 线程任务执行完后,去阻塞队列去任务。
2、计划任务线程池
此线程池会在指定时间对线程进行调度。
//schedule() 在指定时间执行任务
//ss.schedule(myTask, 10, TimeUnit.SECONDS);
//scheduleAtFixedRate() 周期性执行任务
ss.scheduleAtFixedRate(myTask, 2, 2, TimeUnit.SECONDS);
适合场景
周期性的执行任务的场景。
3、单线程线程池
- 核心线程数:1
- 最大线程数:1
- 阻塞队列:LinkedBlockingQueue
适合场景:串行执行任务的场景,一个任务一个任务的执行。
4、可缓存线程池
- 核心线程数为:0
- 最大线程数:Integer.MAX_VALUE
- 阻塞队列为:SynchronousQueue
工作机制:
- 没有核心线程,任务直接添加到SynchronousQueue队列。
- 若有空闲线程,则取出任务执行
- 没有空闲线程,则新建一个线程执行
- 执行完任务,线程再存活60s
适合场景:并发执行大量、短期的小任务
线程池的状态
5种:
Running (接受新任务,处理阻塞队列中的任务)——SHUTDOWN(不会接受任务,但是会处理阻塞队列任务) —— STOP(不会接收、不会处理阻塞队列) —— TIDYING(所有任务已完成)——TERMINATED(线程池彻底终止)