线程池是什么
线程池是值提前创建好若干的线程,让有任务需要处理时,就会分配线程池中的线程去执行这些任务,让任务在执行完成后也不会销毁这个线程,而是会由线程池进行管理,继续等待下一任务提交到线程池。由于创建和销毁线程池都是消耗系统资源的,所以有业务需要频繁的创建线程时,就可以使用线程池来管理这些线程。
使用线程池的好处
1:降低系统资源消耗,通过重复利用已创建的线程执行任务,降低频繁创建销毁线程造成的资源消耗。
2:提高系统的响应速度,当有任务提交到线程池时可以直接分配线程执行,不需要再去创建线程。
3:提高线程的管理性,线程是稀缺的资源,如果无线的创建线程,不仅会造成系统资源的消耗,还会降低系统的稳定性,使用线程池来管理,可以进行统一的资源分配。
线层池使用入门
首先创建一个Runnable接口的实现类
class Demo implements Runnable{
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
通过Executors.newFixedThreadPool方法区创建一个线程池,并制定最大线程数和核心线程数都为5
executorService.execute:提交任务到线程池
在通过线程池去执行这个任务
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
executorService.execute(new Demo());
System.out.println("end ==> "+ Thread.currentThread().getName());
}
输出
end ==> main
pool-1-thread-1
Executor
通过Executors提供了四种创建线程池的方式:
newCachedThreadPool:创建一个线程池,可允许同时运行线程的最大数量为Integer.MAX_VALUE,在60秒内没有新的任务提交到线程池,则这些线程会被回收。
newFixedThreadPool :创建一个定长线程池,可控制线程最大并发数,当提交的任务数超过了最大线程数后会将任务都放在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程的线程池,它只会用唯一的工作线程来执行任务,会保证所有任务按照指定顺序提交的顺序执行。
ThreadPoolExecutor
核心参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:核心的线程数,定义了最小可以同时运行的线程数量。
maximumPoolSize:最大线程数,当队列中存放的任务达到队列的最大容量时,会继续创建线程至最大线程数。
keepAliveTime & unit:当线程池中的线程数大于了核心线程数时,这些多余的线程所存活的最长时间,unit为这个时间的单位。
workQueue:用来存放任务的队列,提交到线程池中的任务会先提交到队列中。
threadFactory:用来创建线程的工厂,通常设置为默认的
handler:用来定义当池中的线程到达了最大线程数,并且队列存放满了后,用来处理继续提交到线程池中任务的策略。
拒绝策略
四种默认的拒绝策略:
AbortPolicy:直接抛出一个RejectedExecutionException类型的RuntimeException异常,通知用户任务呗拒绝了
DiscardPolicy:直接丢弃提交到线程池的任务。
DiscardOldestPolicy:丢弃最早进入队列的任务
CallerRunsPolicy:将任务交给将任务提交到线程池的线程执行
自定义拒绝策略
实现RejectedExecutionHandler接口,并重写rejectedExecution方法,在方法内自定义拒绝处理逻辑
@Slf4j
class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
log.info("====拒绝策略====");
}
}
线程池的工作原理
首先在创建线程池的时候,池内是没有线程的,当用户提交任务到了线程池后,会先将任务提交到队列中,这时会创建一个线程来从队列中取出这个任务并执行,当这个线程执行完任务后,会回来继续监听队列,当再有任务提交到线程池时,会先判断当前池内的线程数是否到达了核心线程数,如果到了核心线程数,就不在继续创建线程,而是使用之前创建的空闲状态的线程执行。如果未达到核心线程数,则会继续创建线程来执行任务,直到创建的线程数到达了设置的核心线程数,这时所创建的线程都会监听队列,当有任务提交到了队列后,线程会将任务取出执行。如果没有任务提交到队列,则所有的线程都阻塞到队列上。
在到达了设置的corePoolSize后,继续提交到线程的任务会直接进入队列中,当提交的任务将将队列填满后,继续提交的任务会创建临时线程来执行,临时线程与核心线程相同,在执行完任务后同样也会监听队列。当临时线程监听队列时间超过设置的keepAliveTime 设置的时间后会将其销毁。但是如果池内的线程数到达了maximumPoolSize设置的线程数后,则不会在继续创建新的线程,这时如果再有任务提交到线程池,则会触发拒绝策略,根据制定的拒绝策略来处理提交的任务