【线程】线程池(三大方法、七大参数、四种拒绝策略)

本文详细介绍了Java线程池的创建方法,包括`Executors`的四种类型及其潜在问题,强调了阿里巴巴开发手册推荐使用`ThreadPoolExecutor`直接创建线程池的原因。线程池的七大参数如核心线程数、最大线程数、存活时间等被详细解析,以及四种拒绝策略的适用场景。最后讨论了线程池的优势,如线程复用、控制并发数,并给出了最大线程数的合理定义方法。

主要就是3大方法、7大参数和4种策略

三大方法

创建只有一个线程的线程池

Executors.newSingleThreadExecutor()

创建固定线程的线程池

Executors.newFixedThreadPool(5)

创建含有5个线程的线程池

创建可以伸缩的线程池

Executors.newCachedThreadPool()

使用线程池创建线程

executorService.execute(()->{
            //方法体
        });

注意

阿里巴巴手册规定不能使用Executors创建线程池,而是通过ThreadPoolExecutor
因为Executors返回的线程池对象有如下弊端

  • FixedThreadPool和SingleThreadPool
    允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量请求,导致OOM
  • CachedThreadPool和ScheduledThreadPool
    允许创建的线程数量为Integer.MAX_VALUE,可能会创建大量线程,导致OOM
    至于为什么,讲到七大参数再提

七大参数

进入三者的源码我们可以发现
在这里插入图片描述
其实三种方法都是调用了ThreadPoolExecutor类的构造方法来创建线程池,而唯一的区别就是三种方法填入的参数不同
接下来我们就来逐一解释一下这几个参数

public ThreadPoolExecutor(int corePoolSize,		//线程池常驻核心线程数
                              int maximumPoolSize,		//线程池能供容纳同时执行的最大线程数
                              long keepAliveTime,		//多余空间线程存活时间
                              TimeUnit unit,		//keepAliveTime的时间单位
                              BlockingQueue<Runnable> workQueue,				//任务队列,被提交但尚未执行的任务
                              ThreadFactory threadFactory,			//表示声场线程池中的工作线程的线程工厂
                              RejectedExecutionHandler handler)			//拒绝策略,表示对列满了并且工作线程大于等于线程池的最大线程数时如何拒绝
  • corePoolSize:线程池中常驻核心线程数

  • maximumPoolSize:线程池能够容纳同时执行的最大线程数

  • keepAliveTime:多余的空闲线程存活时间

  • unit:keepAliveTime的时间单位

  • workQueue:任务队列,被提交但尚未执行的任务

  • threadFactory:表示生成线程池中的工作线程的线程工厂

  • handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何拒绝。

用银行举例子就是

  • corePoolSize就是银行中长时间开启的柜台
  • maximumPoolSize银行中暂时未开放,但是当等待的人多了,就会开放的柜台
  • keepAliveTime就是当因为人多开启多余柜台后,当人数减少了,这个柜台用不到了,当这个柜台用不到多久就关闭
  • workQueue就是在候客区等候的客人
  • handler就是当银行柜台和候客区都满了的时候,如果再来了人怎么处理
    这时候就可以解决上面三个方法的问题了

Executors.newCachedThreadPool

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

我们可以看到

  • 核心线程数为0
  • 最大线程数时INT的最大值(21e)
    这就是手册上所说的,可能会创建大量线程

四种拒绝策略

在这里插入图片描述
我们进入拒绝策略接口,可以看到四个实现类,这就是我们的四种拒绝策略

CallerRunsPolicy

当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。
相当于哪来的去哪里,相当于从公司来的银行,银行让这个人回到公司去办理,也就是mian线程进入满了的话,main线程处理

AbortPolicy

丢弃任务,并抛出拒绝执行 RejectedExecutionException 异常信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行。
相当于银行满了,还有人进来,不处理这个人,并且抛出异常

DiscardPolicy

直接丢弃,其他啥都没有

DiscardOldestPolicy

当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入
与上一个不同的是,当队列满了以后,尝试去和最早的竞争,也不会抛出异常,只不过在抛弃之前多了一次尝试

使用线程池的好处

  1. 线程的复用
    线程的创建和小会对系统来说是巨大的开销,而用线程池管理线程能大大减少这种不易要的开销
  2. 控制线程并发数
    控制线程池中线程的并发数,可以防治大量线程争夺CPU资源造成拥塞
    可以控制线程的最大并发数
  3. 可以对线程进行管理
    线程池可以提供定时定期使用

最大线程应该如何定义

主要有两种方法定义

  • CPU密集型
    CPU有多少个线程最大线程就是几
    注意不要用常量,而是用下面的方法获取核数,因为相同的程序在不同的服务器上可能核数不同
System.out.println(Runtime.getRuntime().availableProcessors());	//输出服务器的核数
### Java线程池参数详解 Java中的`ThreadPoolExecutor`类提供了创建线程池的功能,其构造方法中有个重要参数用于定义线程池的行为。以下是这些参数的作用说明: #### 1. **corePoolSize** 核心线程数是指即使处于空闲状态也会被保留在线程池中的最小线程数量。如果设置了允许核心线程超时(通过`allowCoreThreadTimeOut`),那么核心线程也可能在空闲一段时间后被销毁[^1]。 #### 2. **maximumPoolSize** 最线程数表示线程池中可以容纳的最线程数量。当工作队列已满且当前运行的线程数小于该值时,会继续创建新线程来执行任务。 #### 3. **keepAliveTime** 这是非核心线程闲置后的存活时间。一旦超过这个时间而仍然没有新的任务分配给它们,则会被终止并移除。需要注意的是,只有当线程的数量超过了`corePoolSize`时才会应用此规则;除非启用了前述提到的核心线程超时功能。 #### 4. **unit** 这是一个枚举类型的时间单位,用来指定上面`keepAliveTime`所使用的具体时间尺度,比如秒(`SECONDS`)、毫秒(`MILLISECONDS`)等。 #### 5. **workQueue** 工作队列是用来保存等待被执行的任务的对象集合。常见的实现包括无界阻塞队列 (`LinkedBlockingQueue`) 和有界阻塞队列 (`ArrayBlockingQueue`) 等多种形式。不同的队列策略会影响整个系统的性能表现以及资源消耗情况。 #### 6. **threadFactory** 线程工厂是一个接口,它负责实际创建每一个工作者线程实例的过程。默认情况下使用的是系统自带的标准实现方式,但如果开发者希望自定义某些属性或者行为模式的话就可以提供自己的版本来进行替代操作。 #### 7. **handler** 拒绝策略处理器,在提交任务数超过 `maxmumPoolSize` 并且工作队列已经满了的情况下采取的一种处理机制。JDK 提供了几种内置的选择方案,例如抛异常 (AbortPolicy),调用者自行运行(CallrRunsPolicy)等等。 ```java // 创建一个具有固定小的工作线程池的例子 ExecutorService executor = new ThreadPoolExecutor( 5, // corePoolSize 10, // maximumPoolSize 60L, // keepAliveTime TimeUnit.SECONDS, // unit new LinkedBlockingQueue<>(100), // workQueue Executors.defaultThreadFactory(), // threadFactory new ThreadPoolExecutor.AbortPolicy() // handler ); ``` 上述代码片段展示了如何利用这项配置构建一个简单的线程池实例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值