Java基础之《线程池》

一、谈谈什么是线程池
线程池和数据库连接池非常类似,可以统一管理和维护线程,减少没有必要的开销。
例子:
jdbc请求
select语句---创建jdbc连接---发送jdbc请求(每次都创建非常消耗服务器资源)
一般都会在配置文件中,配置jdbc连接池,配置最小连接数、最大连接数
核心思想:复用机制

二、为什么要使用线程池
因为频繁的开启或停止线程,线程需要重新被cpu从就绪到运行状态调度,效率非常低。所以使用线程池可以实现复用,从而提高效率。

直接提前创建好一些固定的线程数,一直在运行状态,实现复用。从而可以减少线程从就绪到运行状态的切换。

三、你们在哪些地方会使用到线程池
在实际开发项目中,禁止自己取new线程的。如果每次请求过来单独new一个Thread线程,别人找到你这个接口有漏洞,攻击你会导致不停创建线程,cpu撑爆。
小项目用异步线程做通知功能。
大项目必须使用线程池来维护和创建线程。

四、线程池有哪些作用
1、降低资源消耗:通过池化技术重复利用已创建的线程,降低线程创建和销毁造成的损耗。
2、提高响应速度:任务到达时,无需等待线程创建即可立即执行。
3、提高线程的可管理性:线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会因为线程的不合理分布导致资源调度失衡,降低系统的稳定性。使用线程池可以进行统一的分配、调度和监控。
4、提供更多强大的功能:线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池ScheduledThreadPoolExecutor,就允许任务延期执行或定期执行。

五、线程池的创建方式
1、Executors.newCachedThreadPool();  可缓存
2、Executors.newFixedThreadPool();  可定长度
3、Executors.newScheduledThreadPool();  可定时
4、Executors.newSingleThreadExecutor();  单例
底层都是基于ThreadPoolExecutor构造函数封装
实际情况下,不会使用这四种方式,因为它用的是无限队列,会导致线程池溢出
例子:
newCachedThreadPool()核心线程是0,最大线程是无限,它根本没有线程复用

public static ExecutorService newCachedThreadPool(){
    return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>());
}

newFixedThreadPool()至少可以管理线程数

public static ExecutorService newFixedThreadPool(int nThreads){
    return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}

六、线程池底层是如何实现复用的
本质思想:创建一个线程,不会立马停止或者销毁而是一直实现复用。
1、提前创建固定大小的线程一直保持在运行状态:(可能会非常消耗cpu的资源)
2、当需要线程执行任务,将该任务提交缓存在并发队列中。如果缓存队列满了,则会执行拒绝策略。
3、正在运行的线程从并发队列中获取任务执行从而实现多线程复用。

线程池核心点----复用机制
1)提前创建好固定的线程一直在运行状态----死循环实现
2)提交的线程任务缓存到一个并发队列集合中,交给正在运行的线程执行
3)正在运行的线程从队列中获取该任务执行

队列有界和无界区别:
有界队列容量有限,无界队列是没限制 Integer.MAX_VALUE

七、ThreadPoolExecutor核心参数有哪些
corePoolSize:核心线程数,一直正在保持运行的线程
maximumPoolSize:最大线程数,线程池运行创建的最大线程数
keepAliveTime:超出corePoolSize后创建的线程的存活时间
unit:keepAliveTime的时间单位
workQueue:任务队列,用于保持待执行的任务
threadFactory:线程池内部创建线程所用的工厂
handler:任务无法执行时的处理器

八、线程池创建的线程会一直在运行状态吗?
不会
例如:配置核心线程数corePoolSize为2,最大线程数maximumPoolSize为5,我们可以通过配置超出corePoolSize核心线程数后创建的线程的存活时间,例如为60s,创建的线程在60s内一直没有任务执行,则会停止该线程

九、为什么阿里巴巴不建议使用Executors
因为默认的Executors线程池底层是基于ThreadPoolExecutor构造函数封装的,采用无界队列存放缓存任务,会一直缓存任务容易发生线程池队列溢出

十、线程池ThreadPoolExecutor底层实现原理
1、当线程数小于核心线程数时,创建线程
2、当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列
3、当线程数大于等于核心线程数,且任务队列已满
3.1、若线程数小于最大线程数,创建线程
3.2、若线程数等于最大线程数,抛出异常,拒绝任务

十一、线程队列满了,任务会丢失吗
如果队列满了,且任务总数大于最大线程数则当前线程走拒绝策略
可以自定义拒绝异常,将该任务缓存到redis、本地文件、mysql中后期实施补偿

十二、线程池有哪些拒绝策略
1、AbortPolicy:丢弃任务,抛运行时异常
2、CallerRunsPolicy:重试添加当前的任务,直到成功
3、DiscardPolicy:直接抛弃,没有异常信息
4、DiscardOldestPolicy:从队列中踢出最先进入队列(最后一个执行)的任务
5、实现RejectedExecutionHandler接口,可自定义处理器,缓存起来
 

参考资料:
https://www.zhihu.com/question/23212914/answer/245992718
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值