线程池的创建方式、七个参数、拒绝策略、阻塞队列、线程池大小设定

线程池的创建方式

1、通过Executors的静态方法可以创建四种类型的线程池。(不推荐)

1)FixedThreadPool 创建一个固定线程数的线程池,线程数量一直保持固定不变,如果任务提交时,没有空闲线程,那就进入任务队列,当有空闲时间时,再执行任务队列中的任务。

2)SingleThreadExecutor 线程池中始终只有一条线程。

3)CachedThreadPool 根据实际情况调整线程的数量,默认初始为0,当有任务提交时,创建线程去执行,当任务执行完毕,默认空闲等待60秒没有新任务提交就被销毁。

4)ScheduledThreadPool 可以在给定的延迟后或者定时运行任务。

PS:上面四种的任务队列长度最大都是Integer.MAX_VALUE,可能造成大量的请求堆积,从而OOM.

补充:前两个使用的是无界队列,队列最大是Integer.MAX_VALUE,第三个的最大线程数是Integer.MAX_VALUE,第四个是无界延迟队列,队列最大是Integer.MAX-VALUE。

2、使用ThreadPoolExecutor()创建线程池。(推荐)

1)七个参数

corePoolSize 核心线程数,任务队列未到达最大容量时,最大可运行线程数。

maximumPoolSize 最大线程数,任务队列达到最大线程数时,最大可运行线程数。

keepALiveTime 存活时间,核心线程数之外的空闲线程存活时间

unit 时间单位,存活时间的时间单位

workQueue 任务队列,暂存等待执行的任务

threadFactory 线程工厂,用来创建线程,一般使用默认的

handler 拒绝策略,当达到最大线程数并且任务队列达到最大容量时,提交的任务会被拒绝,使用相应的拒绝策略。

PS:

线程池默认线程数量是0,当有任务提交时,会创建线程

当线程数达到核心线程数时,还有任务提交,会被暂存在先入先出的任务队列,保证有序性

当任务队列达到最大容量时,继续创建线程,线程达到最大线程数时,新提交的任务同样会进入任务队列

当任务队列再次达到最大容量时,使用拒绝策略

当线程执行完之后,空闲线程超过设置的存活时间,会被回收,直到线程数减少到核心线程数,回收才会停止

2) 拒绝策略

ThreadPoolExecutor.AbortPolicy: 抛出异常拒绝新任务。

ThreadPoolExecutor.CallerRunsPolicy:使用当前主线程执行新任务,慎选。

ThreadPoolExecutor.DiscardPolicy:直接丢弃新任务。

ThreadPoolExecutor.DiscardOldestPolicy:丢弃最早的新任务,也就是任务队列中最早未被处理的任务。

阻塞队列

LinkedBlockingQueue(基于链表的无界队列)

FixedThreadPool和ISingleThreadExecutor使用的是这种队列,队列最大可以达到Integer.MAX_VALUE,导致OOM。

SynchronousQueue(同步队列)

CacheThreadPool 使用的是这种队列,他不存放元素,当有新任务来时,有空闲线程就是用空闲线程,否则就创建线程,线程数最大也可以达到Integer.MAX_VALUE,导致创建大量的线程,导致OOM。

DelayedworkQueue(延迟阻塞队列)

ScheduleThreadPool使用这种线程,内部元素会按照定时时间先后排序,保证每次出队列的执行时间是最早的,内部会自动扩容,最大扩容到Integer.MAX_VALUE,导致OOM。

线程池的大小设定

对于CPU密集型任务,一般设定为N+1,多出来一条用来保证某个线程因为其他原因而暂停,让这一条去占用CPU执行任务,充分利用CPU空闲时间。

对于I/O密集型任务,一般设定为2N,与I/O 交互,需要等待I/O的响应,可以让出CPU,切换线程。

  • 57
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以通过将自定义的拒绝策略添加到线程池阻塞队列中来实现。在Java中,线程池阻塞队列通常使用`BlockingQueue`接口的实现类。下面是一种常见的做法: 1. 创建一个实现了`RejectedExecutionHandler`接口的自定义拒绝策略类,例如`CustomRejectedExecutionHandler`。 2. 在自定义拒绝策略类中,重写`rejectedExecution`方法,该方法会在任务被线程池拒绝执行时被调用。在该方法中,你可以根据需求对被拒绝的任务进行处理,例如将其添加到阻塞队列中。 3. 创建一个线程池,使用`ThreadPoolExecutor`类。在创建线程池时,可以指定阻塞队列的实现类,并将自定义的拒绝策略对象作为参数传递给线程池构造函数。 以下是一个示例代码: ```java import java.util.concurrent.*; public class CustomRejectedExecutionHandler implements RejectedExecutionHandler { private final BlockingQueue<Runnable> queue; public CustomRejectedExecutionHandler(BlockingQueue<Runnable> queue) { this.queue = queue; } @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { try { queue.put(r); // 将被拒绝的任务添加到阻塞队列中 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } public class Main { public static void main(String[] args) { int corePoolSize = 5; int maximumPoolSize = 10; long keepAliveTime = 5000; BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100); RejectedExecutionHandler rejectionHandler = new CustomRejectedExecutionHandler(queue); ThreadPoolExecutor threadPool = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, queue, rejectionHandler ); // 使用线程池执行任务 threadPool.execute(() -> { // 任务逻辑 }); } } ``` 在上面的示例中,自定义拒绝策略类`CustomRejectedExecutionHandler`将被拒绝的任务添加到阻塞队列中。然后,创建一个`ThreadPoolExecutor`线程池,并将阻塞队列和自定义的拒绝策略对象传递给构造函数。 这样,当线程池无法接受新任务时,会调用自定义的拒绝策略,并将被拒绝的任务添加到阻塞队列中。这个阻塞队列将会在有空闲线程时被持续消费执行。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值