线程池构造方法的认识

简介: 线程池构造方法的认识

线程池中构造方法的认识



标准库中提供了一个ThreadPoolExecutor类,这个类中最复杂的就是构造方法,而且这个类中由于构造方法过于复杂

而且有缺陷,所以就对外提供了创建实例的 “工厂方法” ,这样的方法其实就是普通的静态方法.

工厂方法的内部有给我们提供构造想要的实例的代码实现,所以我们只需要通过工厂方法的方法名来获取我们想要的实例即可.

线程池是Java标准库中的Java.util.concurrent.ThreadPoolExecutor类中.

标准库中提供了一个 Java.util.concurrent.ThreadPoolExecutor类

这个类中的构造方法比较多,我们主要了解参数最多最复杂的那个构造方法

我们来一个一个的解释:

corePoolSize 核心线程数和maxmumPoolSize最大线程数分别都是什么?都有什么区别?

corePoolSize (核心线程数)

corePoolSize 是线程池的基本大小,表示在没有任务执行时,线程池维护的线程数。即使这些线程当前处于空闲状态,它们也会被保留在池中。

当有新任务提交到线程池时,如果当前池中的线程数小于 corePoolSize,则会创建一个新线程来执行任务,即使其他线程处于空闲状态。

如果任务数超过 corePoolSize,而任务队列未满,新任务将被放入任务队列而不是新建线程(除非线程池已满)。

maximumPoolSize(最大线程数)

maximumPoolSize 表示线程池的最大大小,即线程池中允许的最大线程数。

当任务队列已满且池中线程数小于 maximumPoolSize 时,线程池会创建新的线程来执行任务,直到达到最大线程数。

超过最大线程数的任务将被拒绝(默认是抛出 RejectedExecutionException 异常,但可以通过设置拒绝策略来进行不同的处理)。

  • 区别:

在池中运行的线程数将在 corePoolSize 和 maximumPoolSize 之间进行动态调整。

当任务数增加时,线程池会尽可能地扩展到 maximumPoolSize;当任务数减少时,线程池会逐渐收缩到 corePoolSize。

corePoolSize 提供了一种在任务轻量时保持一定线程数的机制,以提高任务的响应速度。

而 maximumPoolSize 提供了在负载较大时临时增加线程数以处理额外任务的机制。

在构建 ThreadPoolExecutor 时,合理设置 corePoolSize 和 maximumPoolSize 是关键,以确保线程池能够在不同负载下表现出理想的性能。

keepAliveTime(非核心线程的空闲超时时间)

  • keepAliveTime 表示非核心线程的空闲超时时间,即当线程池中的线程数大于核心线程数时,
    空闲的非核心线程在经过一定时间后会被终止并从线程池中移除。
  • 如果线程池的线程数超过核心线程数,但有一些线程在一段时间内没有执行任务,
    这些线程就被认为是空闲的。keepAliveTime 就是指定这些空闲线程的最大存活时间。

TimeUnit

  • TimeUnit 是一个枚举类型,用于表示时间单位。它规定了 keepAliveTime的时间单位,
    包括 NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS、MINUTES、HOURS 和 DAYS。
  • 当设置 keepAliveTime 时,需要同时指定时间单位,以便正确地解释超时时间。
    例如,通过设置 TimeUnit.SECONDS可以将超时时间单位设置为秒。

workQueue

workQueue 是 ThreadPoolExecutor 中的一个参数,用于指定任务队列。

线程池的任务队列主要用于存储提交但尚未被执行的任务。用户可以手动传入一个任务队列,

这样可以根据实际需求选择不同的队列实现,以满足特定的场景和性能要求。例如,在某些场景下,对响应时间要求较高,可以选择同步队列;而在某些场景下,

对系统资源的使用有更高的要求,可以选择有界队列或无界队列。手动传入任务队列是为了提供更大的灵活性和定制性。

这个参数允许用户自定义创建新线程的方式,从而可以控制线程的创建过程,包括线程的名字、优先级、守护状态等。

threadFactory

threadFactory 参数是一个实现了 ThreadFactory 接口的对象。ThreadFactory 是一个简单的接口,它只有一个方法:Thread newThread(Runnable r)。当线程池需要创建一个新线程时,会调用这个方法。

RejectedExecutionHandler拒绝策略

线程池的拒绝策略

线程池的任务队列已经满了(工作线程已经忙不过来了)如果又有别人

往里面添加新的任务,怎么办?

  • 这个策略对于我们实现高并发服务器,是十分有意义的

Java中的线程池在面临无法接受新任务的情况时,会执行拒绝策略。

拒绝策略定义了在线程池饱和时如何处理新任务的策略。

ThreadPoolExecutor 提供了几种内置的拒绝策略,同时也允许用户自定义拒绝策略。

以下是Java中常见的拒绝策略:

  1. AbortPolicy(默认策略):
  • AbortPolicy是 ThreadPoolExecutor的默认拒绝策略。
    当任务无法被提交时,会抛出 RejectedExecutionException 异常。
  1. CallerRunsPolicy:
  • CallerRunsPolicy拒绝策略将会把任务返回给提交任务的线程执行。这种方式,
    虽然可能导致调用线程变慢,但是不会抛出异常。
  1. DiscardPolicy:
  • DiscardPolicy拒绝策略会默默地丢弃无法处理的任务,不会抛出异常。
  1. DiscardOldestPolicy:
  • DiscardOldestPolicy拒绝策略会丢弃队列中等待时间最久的任务,然后将新任务加入队列。同样,不会抛出异常。

用户还可以通过实现 RejectedExecutionHandler 接口来定义自己的拒绝策略。

自定义拒绝策略需要实现 RejectedExecutionHandler接口的 rejectedExecution方法,

该方法定义了任务被拒绝时的处理逻辑。

示例代码:

public class CustomRejectedHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // 自定义处理逻辑,例如记录日志、通知等
        System.err.println("Task rejected: " + r.toString());
    }
}
// 使用自定义拒绝策略
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize,       // 核心线程数
    maximumPoolSize,    // 最大线程数
    keepAliveTime,      // 非核心线程的空闲超时时间
    TimeUnit.SECONDS,   // 时间单位
    workQueue,          // 任务队列
    new CustomRejectedHandler()  // 自定义拒绝策略
);

目录
相关文章
|
2月前
|
Java 调度
【多线程-从零开始-贰】线程的构造方法和常见属性
【多线程-从零开始-贰】线程的构造方法和常见属性
22 0
|
7月前
|
Java API
线程池(关于变量捕获、线程数、针对ThreadPoolExecutor的构造方法参数的解释、自实现线程池)
线程池(关于变量捕获、线程数、针对ThreadPoolExecutor的构造方法参数的解释、自实现线程池)
|
Java API 开发者
java多线程系列(3)线程构造方法(源码剖析)
在上一篇文章中对线程状态生命周期和常见的线程api进行了一个讲解。这篇文章开始着重对其构造方法进行一个说明,也将揭晓为什么我们调用了start方法就能启动一个线程。
147 0
java多线程系列(3)线程构造方法(源码剖析)
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
58 1
C++ 多线程之初识多线程
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
27 3
|
2月前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
23 2
|
2月前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
38 2
|
2月前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
44 1
|
2月前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
50 1
|
2月前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
31 1