如何自定义线程池,以及注意事项

线程每次创建和关闭的开销非常大,我们可以使用线程池来管理我们的线程,可以充分利用线程,减少不必要的开销。

创建线程的方式有三种:

1、继承Thread类

2、实现Runable或者Callable(带返回值)接口

3、线程池的方式启动

今天我们主要针对线程池来进行展开讨论:

JDK自带创建线程的方式有多种:

 这里是针对JDK1.8版本。每个创建都不一样,但是使用JDK自带的线程池会出现OOM问题,中小型公司一般狠难遇到,在阿里巴巴开发文档上面有明确的标识:

 如果有需要此文档,请点击下面的url进行下载:https://www.cnblogs.com/han-1034683568/p/7680354.html

既然JDK自带的线程池我们不能用,那么我们要自己手动来写线程池了, 如果创建一个线程池:

下面的是对应的七个参数:

ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

 我们可以这样来创建线程池,其他里面的参数表示什么意思,我们在这里说明一下啊:

corePoolSize:线程中常驻核心线程数
maximumPoolSize:线程池能够容纳同时执行的最大线程数,此值必须大于1
keepAliveTime:多余空闲线程的存活时间,
unit:keepAliveTime的单位
workQueue:任务队列,被提交但尚未被执行的任务
threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程,一般的默认即可
handler:拒绝策略,表示当队列满了,并且工作线程大于等于线程池的最大线程数(maximumPoolSize)
总体步骤:
1、在创建线程后,等待提交过来的任务请求
2、当调用execute()方法添加一个请求任务的时候,线程池会如何判断
  2.1、如果正在运行的线程数小于
corePoolSize,那么马上创建线程运行这个认为
  2.2、如果正在运行的线程数大于等于corePoolSize,那么将这个认为放入队列
  2.3、如果这个时候队列满了,且小于maximumPoolSize,那么还是要创建线程立即执行任务
  2.4、如果队列满了,maximumPoolSize也满了,将会启动饱和拒绝策略来执行
3、将一个线程完成任务的时候,他会冲=从队列里面取下一个任务来执行
4、当一个线程无事的时候,超过一定时间的时候,线程池会判断:如果当前运行的线程数大于等于corePoolSize,那么这个线程将被停掉,所以线程池的所有任务完成后它最终收缩到corePoolSize的大小

线程池的拒绝策略:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。(默认)
ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务

添加阻塞队列的方式有四种:

  1、add,添加不进去的时候,就会抛异常
  2、offer,添加进去返回true,添加不进去返回false
  3、put,会一直阻塞,直到可以放进去为止
  4、offer+时间,如果阻塞队列满的时候,往阻塞队列添加,多久没有添加进去,则停止添加

如何合理的配置线程池:
  这看你的业务了,看你的业务是CPU密集还是IO密集
  如果是CPU密集,一般配置的是CPU的核数或者核数+1
  如果是IO密集,大部分的线程都会阻塞,则需要多配置线程数,公式(CPU/(1-阻塞系数)),阻塞系数在0.8-0.9之间,比如8核CPU:8/(1-0.9) = 80个线程



 

猜你喜欢

转载自www.cnblogs.com/ltstar/p/12691125.html