Java基础笔记(三)线程池连环炮

一、四种常见的线程池

1、CachedThreadPool:可缓存的线程池

创建方法:

ExecutorService mCachedThreadPool = Executors.newCachedThreadPool();

1.这种线程池内部没有核心线程,非核心线程的数量为Integer.max_value,线程的数量是有没限制的。
2.在创建任务时,若有空闲的线程时则复用空闲的线程,若没有则新建线程。
3.没有工作的线程(闲置状态)在超过了60S还不做事,就会销毁。

2、FixedThreadPool:定长的线程池

创建方法:

//nThreads => 最大线程数即maximumPoolSize
ExecutorService mFixedThreadPool= Executors.newFixedThreadPool(int nThreads);

1、该线程池的最大线程数等于核心线程数,所以在默认情况下,该线程池的线程不会因为闲置状态超时而被销毁。
2、如果当前线程数小于核心线程数,并且也有闲置线程的时候提交了任务,这时也不会去复用之前的闲置线程,会创建新的线程去执行任务。如果当前执行任务数大于了核心线程数,大于的部分就会进入队列等待。等着有闲置的线程来执行这个任务。

3、SingleThreadPool:一个单线程化的线程池

创建方法:

ExecutorService mSingleThreadPool = Executors.newSingleThreadPool();

1、有且仅有一个工作线程执行任务
2、所有任务按照指定顺序执行,即遵循队列的入队出队规则

4、SecudleThreadPool:周期性执行任务的线程池

创建方法:

//nThreads => 最大线程数即maximumPoolSize
ExecutorService mScheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);

1、不仅设置了核心线程数,最大线程数也是Integer.MAX_VALUE。
2、这个线程池是唯一个有延迟执行和周期执行任务的线程池。

二、线程池的工作原理

一般来说(以FixedThreadPool举例):
如果我设置的核心线程数的大小为10
一个任务进入以后,发现只有3个核心线程,则新建一个核心线程执行任务
如果有10个核心线程,则加入队列,待那个核心线程空闲以后,获取任务执行
如果队列也满了,看看线程池满了没,没满创建非核心线程执行
如果线程池也满了了,调用拒绝策略拒绝策略
如下图:
在这里插入图片描述

三、参数解读

int corePoolSize:该线程池中核心线程数最大值

核心线程:线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程,如果超过corePoolSize,则新建的是非核心线程核心线程默认情况下会一直存活在线程池中,即使这个核心线程啥也不干(闲置状态)。
如果指定ThreadPoolExecutor的allowCoreThreadTimeOut这个属性为true,那么核心线程如果不干活(闲置状态)的话,超过一定时间(时长下面参数决定),就会被销毁掉。

int maximumPoolSize: 该线程池中线程总数最大值

线程总数 = 核心线程数 + 非核心线程数。

long keepAliveTime:该线程池中非核心线程闲置超时时长

一个非核心线程,如果不干活(闲置状态)的时长超过这个参数所设定的时长,就会被销毁掉,如果设置allowCoreThreadTimeOut = true,则会作用于核心线程。

queue:

选择的队列
BlockingQueue workQueue:
该线程池中的任务队列:维护着等待执行的Runnable对象当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务。
常用的workQueue类型:
SynchronousQueue:
这个队列接收到任务的时候,会直接提交给线程处理,而不保留它如果所有线程都在工作怎么办?那就新建一个线程来处理这个任务!所以为了保证不出现<线程数达到了maximumPoolSize而不能新建线程>的错误,使用这个类型队列的时候,maximumPoolSize一般指定成Integer.MAX_VALUE,即无限大
LinkedBlockingQueue:
这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了maximumPoolSize的设定失效,因为总线程数永远不会超过corePoolSize
ArrayBlockingQueue:
可以限定队列的长度,接收到任务的时候,如果没有达到corePoolSize的值,则新建线程(核心线程)执行任务,如果达到了,则入队等候,如果队列已满,则新建线程(非核心线程)执行任务,又如果总线程数到了maximumPoolSize,并且队列也满了,则发生错误
DelayQueue:
队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务

TimeUnit unit:keepAliveTime的单位

TimeUnit是一个枚举类型,其包括:
NANOSECONDS : 1微毫秒 = 1微秒 / 1000
MICROSECONDS : 1微秒 = 1毫秒 / 1000
MILLISECONDS : 1毫秒 = 1秒 /1000
SECONDS : 秒
MINUTES : 分
HOURS : 小时
DAYS : 天

ThreadFactory threadFactory:

创建线程的方式,这是一个接口,你new他的时候需要实现他的Thread newThread(Runnable r)方法,一般用不上。

RejectedExecutionHandler handler:

出现异常时的拒绝策略。
有四种:
第一种AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满
第二种DisCardPolicy:不执行新任务,也不抛出异常
第三种DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行
第四种CallerRunsPolicy:直接调用execute来执行当前任务

四、面试题

如果在线程池中使用LinkedBlockingQueue(无界阻塞队列)会有什么问题?

如果线程处理速度慢,队列会变得特别长,可能会内存飙升或内存溢出

线程池队列满了会有什么问题?

1、如果规定了线程池大小,接下来线创建核心线程,线程池满了。会走异常处理
2、如果没规定线程池大小,会一直创建非核心线程,如果线程创建的足够多,一个线程一个栈,会导致栈内存溢出,如果内存没有一处,也会导致CPU过载,可能会导致服务器宕机

上述两个问题,解决办法,在线程居多的时候,可以使用自定义拒绝策略持久化到磁盘中,等线程数量下来以后读取执行。

如果线上机器突然宕机,线程池的阻塞队列怎么办?

必然会导致线程池里积压的任务丢失
怎么解决?
还是持久化到数据库中。任务进入队列时,将其信息插入数据库,更新状态为未提交。当任务提交到线程执行完毕后,更新为已提交。宕机后重启,高一个后台线程,扫描未提交的任务,提取信息,重新执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值