线程池详解

线程池详解,第1张

线程池详解 为什么要用线程池?

如果每次用到线程都是new Thread()的话,会导致线程频繁地创建和销毁,加高系统负载;而且线程是有限的稀缺资源,如果耗尽,会导致CPU load过高。

而线程池可以复用线程,避免线程的频繁创建和销毁;线程池可以设置最大线程数,避免线程数量过大。

JUC中的线程池实现:

具体实现类可以参考JUC下的Executors类,Executors中提供了很多静态方法,通过这些静态方法可以获取指定类型的线程池。比如常见的有:

FixedThreadPool:创建一个线程数量固定的线程池;

SingleThreadPool: 创建由一个线程组成的线程池;

CachedThreadPool: 创建一个线程缓存池,线程数量无上限,但是也可以复用以前的线程。

或者干脆自己来new ThreadPoolExecutor(...)。

线程池的工作原理:

线程池里面有很多线程,线程的数量可以是固定的,也可以是浮动的,具体依据参数而定;同时线程池维护了一个任务队列。工作原理就是线程池中的线程从队列中取到任务,然后执行。具体见图:

1、主线程把任务(任务是实现Runnable或Callable的东西)提交到线程池;

2、此时如果核心线程数没有饱和,首先会开启新的核心线程,来执行这个任务;

3、如果核心线程数达到了饱和,那么此时会把任务放到任务队列中去,比如linkedBlockingQueue等;

4、如果任务队列也满了,则开启非核心线程,来执行该任务;

5、如果非核心线程数也饱和了,则走拒绝策略。

线程池常见参数及使用:

查看JUC下的ThreadPoolExecutor源码:

corePoolSize: 核心线程数,随着第一次任务的执行而创建,如果没有任务执行就阻塞在阻塞队列处等待任务,永远不会销毁。

maximumPoolSize: 最大线程数,为了抵御高峰期任务过多的情况,在任务队列满了的情况下创建产生,没有任务可执行后,阻塞在队列处等待任务,超过最大空闲时间之后,被销毁。

keepAliveTime、unit: 给非核心线程设置的最大空闲时间。

workQueue:任务队列,选择合适的队列来存放任务,线程池中的线程会从这里取任务。有很多种任务队列。感觉有点生产者、消费者的意思:主线程让任务队列中生产任务,线程池线程从队列中消费任务。这里的workQueue就类似于rabbitMQ中的工作队列消息分发模型。

threadFactory: 线程池创建线程的工厂,比如可以在里面可以进行给创建的每个线程命名等 *** 作。

handler: 当队列满了,并且已达到最大线程数,不能创建新线程了,此时采取的拒绝策略,有以下四种常用策略:

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常;

ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常;

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务;

ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务。

常见问题: 如果无界阻塞队列中任务无限积压会导致什么后果?

如果使用的任务队列是:linkedBlockingQueue,这个列队是一个无界阻塞队列。

如果任务提交的速度高于任务处理的速度,那么会有越来越多的任务积压在这个队列里面,并且走不到开启非核心线程的那一步。这样下去会发生什么情况呢?

线程池的任务队列中的对象也是存储在JVM内存中的,如果队列中的任务越来越多、无限积压,那么必然OOM,迟早OOM。

如果线程池中的线程过多会导致什么后果?

如果设定参数:maximumPoolSize: Integer.MAX_VALUE

线程池中线程过多,第一,因为线程本身是需要栈内存的,如果线程数量无限飙升,也会导致OOM的;第二,线程数量过多,会导致CPU 负载过高。

实际生产实践中要根据业务负载,设置合适的corePoolSize、maximumPoolSize,选择合适的workQueue。如果业务负载过高,就应该考虑增加服务实例,从而解决这样的问题。

如果线程池所在机器突然宕机,会导致什么后果?

线程池中的任务队列是在内存中的,对于服务实例来说,一般不存储数据,线程池中的任务列队算是存储了任务数据,机器宕机,必然导致线程池中的任务数据丢失。

解决方案:将任务存储存储磁盘来,比如:每次往任务列队中放数据的时候,同时也往数据库中写入任务,可以创建一个专门为线程池的任务队列服务的任务表,标明任务的处理状态,宕机恢复后,起一个后台线程,扫描任务表中未处理的任务,然后重新放入线程池。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5709013.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存