线程池详解

为什么要用线程池?

如果每次用到线程都是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。如果业务负载过高,就应该考虑增加服务实例,从而解决这样的问题。

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值