线程池常见问题总结
Posted You295
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池常见问题总结相关的知识,希望对你有一定的参考价值。
线程池
一:线程池的概念
线程的创建和销毁都需要映射到操作系统,故付出的代价很高。为了避免频繁的创建线程,销毁线程以及方便线程的管理需要,线程池则应用而生。
二:线程池的优点
1)降低销毁资源:重复利用线程池中已经存在的线程,减少了线程的创建和消亡造成的性能开销。
2)提高了相应速率:当任务到达时,任务可以不需要等到线程创建就能够执行。
3)防止服务器过载:形成内存溢出,或者cpu耗尽。
4)提高线程的可管理性:线程时稀缺资源,若无限的创建线程,不仅会消耗资源,还会降低系统的稳定性,使用线程池可以统一的分配,调优和监控。
三:常见的线程池
1.CachedThreadPool
缓存池线程,如果线程池的长度超过处理需要,可灵活回收空闲线程,若无可回收,则创建新的线程。
public static void main(String[] args)
ExecutorService pool = Executors.newCachedThreadPool();//创建对象
for(int i=0;i<=8;i++)
pool.execute(() ->
for(int j=0;j<=9;j++)
System.out.println(Thread.currentThread().getName()+">>>"+j);
);
2.NewSingleThreadPool
单线程池线程。线程池中心只有一个线程,线程执行完任务立即回收,只会用唯一的工作线程来执行任务,保证所有的任务按照指定顺序。
public static void main(String[] args)
ExecutorService pool = Executors.newSingleThreadExecutor();
for(int i=0;i<=8;i++)
pool.execute(() ->
for(int j=0;j<=9;j++)
System.out.println(Thread.currentThread().getName()+">>>"+jz);
);
3.NewFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
public static void main(String[] args)
ExecutorService pool = Executors.newFixedThreadPool(6);
for(int i=0;i<=9;i++)
pool.execute(() ->
for(int j=0;j<=9;j++)
System.out.println(Thread.currentThread().getName()+">>>"+j);
);
4.NewScheduleThreadPool
创建一个定长线程池(普通线程数量无线),适用于定时及周期性任务执行。
public static void main(String[] args)
ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
pool.scheduleAtFixedRate(()->
System.out.println(new Date());
, 0, 1, TimeUnit.SECONDS);
四:线程池的配置参数
1)corePoolSize:核心线程数
a:核心线程会一直存活,及时没有任务需要执行。
b:当线程数小于核心线程数时,即使有线程空闲,线程池会优先创建新线程处理。
c:设置allowCoreThreadTimeout = true(默认false)时,核心线程会超时关闭。
2)queueCapacity:任务队列容量(阻塞队列)
a:当核心线程数达到最大时,新任务会放在队列中排队等执行。
3)maxPoolsize:最大线程数
a:当线程数>=corePoolSize,且任务队列已满时。线程池会创建新的线程来处理任务。
b:当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常。
4)keepAliveTime:线程空闲时间
a:当线程空闲时间达到:keepAliveTime时,线程会退出,直到线程数=corePoolSize.
b):如果allowCoreThreadTimeout=true,则会直到线程数量等于0;
5)allowCoreThreadTimeout:允许核心线程超时
6)rejectedExecutionHandler:任务拒绝处理器
a:两种情况会拒绝处理任务:
1.当线程数已经达到maxPoolSize,并且队列已满,会拒绝新的任务。
2.当线程池被调用shutdown()后,会等待线程池里的技术执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会直接拒接新任务。
b:线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常。
c):ThreadPoolExecutor类有几个内部实现类来处理这类情况:
1:AbortPolicy 丢弃任务,抛运行时异常。
2:CallerRuns Policy执行任务
3:DiscardPolicy 忽视,什么都不会发生
4:DiscardOldestPolicy 从队列中踢出最先进队列(最后一个执行)的任务
d)实现RejectedExecutionHandler 接口,可自定义处理器。
五:线程池的工作流程
1)当提交一个新的任务到线程池时,线程池判断corePoolSize线程池是否都在执行任务,如果有空闲的线程,则从核心线程池中取一个线程来执行此任务,直到当前线程数等于corePoolSize;
2)如果当前线程数量为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;
3)如果阻塞队列满了,那就创建新的线程执行当前任务,直到线程池中的线程数达到maxPoolSize,这时候再有任务来,就由饱和策略来处理提交的任务。
六:线程池的拒绝策略
当线程池workQueue已满且无法再创建新的线程池时,就要拒绝后续的任务,拒绝策略实现了RejectedExecutionHandler 接口。
七:为什么要使用线程池
1)减少了创建和销毁的次数,每个工作线程都可以被重复利用,可执行多个任务。
2)可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后导致电脑死机)。
以上是关于线程池常见问题总结的主要内容,如果未能解决你的问题,请参考以下文章