线程池学习

三个思考问题:

1.怎么设置线程池的容量大小?

2.线程池添加任务的流程?

3.怎么设置核心线程数的大小?

 

线程池中Executor、ExecutorService、Executors三者的区别

(1)Executors类提供工厂方法创建不同类型的线程池,比如:

newSingleThreadExecutor():创建一个只有一个线程的线程池。

newFixedThreadPool(int numOfThreads)来创建固定线程数的线程池。

newScheduleThreadPool(int corePoolSize):创建一个线程池,它可以安排在给定延迟或者定期地执行。

newCacheThreadPool()创建一个可缓存的线程池,如果线程池长度超过处理需要,可以灵活回收空闲线程,若无可回收,则新建线程(默认60s收回,适用于执行很多短期异步任务的程序,长时间保持空闲的线程池不会使用任何资源)

(2)ExecutorService接口继承了Executor接口,是Executor的子接口。ExecutorService除了允许客户端提供一个任务,还提供了用来控制线程池的方法,比如 调用 shutDown() 方法终止线程池。

什么是线程池:juc提供了一个 java.util.concurrent.Executor接口实现用于创建线程池。

阿里手册中强制不允许用Executors创建线程池:

原因是:

a.创建FixedThreadPool和SingleThreadPool 允许的请求队列长度是Integer.MAX_VALUE,可能会造成大量堆积请求,造成OOM。

b.创建CacheThreadPool和ScheduleThreadPool 允许创建的线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而OOM。

那么怎么创建线程池呢?通过ThreadPoolExecutor的方式,这样子的处理方法让写的同学更加明确线程池的运行的运行规则。规避资源耗尽的风险。

AbstractExecutorService 实现了ExecutorService接口,ThreadPoolExecutor 继承AbstractExecutorService 

ThreadPoolExecutor 构造方法几个核心参数:

1.corePoolSize:线程池的常驻核心线程数。

2.maxinumPoolSize:线程池能够容纳的最大线程数,这个值必须大于1.

3.keepAliveTime:多余的空闲线程的存活时间,当空闲时间达到keepAliveTime的时候,多余空闲线程被销毁直到只剩下corePoolSize个线程为止。

4.unit:keepAliveTime的单位。

5.workQueue:任务队列表示尚未被执行的任务。

6.threadFactory:表示生成线程池中工作线程的工厂,一般用线程池默认的线程池工厂。

7.handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数时。

 

解答开头问题1:

线程池的大小由上面的参数2决定

 

解答开头问题3:

线程池核心线程数的大小由上面的参数1决定

 

解答开头问题2-线程池添加队列的过程:

1.线程池创建后,提交任务给线程池,线程池判断当前线程数是不是达到核心线程数,如果没有达到,则线程池创建新的线程。

2.如果CoreSize加到已满,会将加入的任务放到任务队列中,此时核心线程会通过take阻塞的形式从任务队列中获取任务执行。

3.如果任务队列已经满了,核心线程处理消耗不掉,则线程池会通过pool(time,unit)的方式创建临时线程,如果临时线程在指定的时间获取到队列中的任务进行执行,则该线程被释放。

4.如果临时线程一直增加,和核心线程之和达到设定的最大线程数,则继续放入队列的任务会被预设的拒绝策略进行处理。

四种拒绝策略:

1.丢弃:ThreadPoolExecutor.DiscardPolicy

2.替换最老的那个请求:ThreadPoolExecutor.DiscardOldestPolicy()

3.报错,抛出异常:ThreadPoolExecutor.AbortPolicy()

4.重试,自动重复调用execute方法:ThreadPoolExecutor.CallerRunsPolicy(),它直接在execute 方法的调用线程中运行被拒绝的任务,如果执行程序已关闭,则会丢弃该任务。

 

那么应该有多少个线程?

Runtime.getRuntime().availableProcessors()其实有点粗暴,并没有考虑到程序是cpu密集型还是I/O密集型

正常来说,

线程数 = CPU 核心数 *( 1 - IO 阻塞系数)

线程数并不是越多越好,要考虑线程切换的开销。

(什么是cpu或i/o计算密集型?

一般来说程序一般是cpu和I/O操作交互执行的,一般I/O操作比cpu计算慢很多,这种场景一般称为I/O密集型,相对的就是cpu计算机密集型。)

I/O 密集 型程序和 CPU 密集型程序,计算最佳线程数的方法是不同的。

CPU 密集型程序:理论上“线程的数量 =CPU 核数”就是最合适的,不过在工 程上,线程的数量一般会设置为“CPU 核数 +1”,这样的话,当线程因为偶尔的内存页失效或 其他原因导致阻塞时,这个额外的线程可以顶上,从而保证 CPU 的利用率。

I/O 密集 型程序:

最佳线程数 =1 +(I/O 耗时 / CPU 耗时

不过上面这个公式是针对单核 CPU 的,至于多核 CPU,也很简单,只需要等比扩大就可以了, 计算公式如下:

最佳线程数 =CPU 核数 * [ 1 +(I/O 耗时 / CPU 耗时)]

参考:https://www.jianshu.com/p/f5ead62827d7

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值