Java 线程池作用及类型

简介: 线程池的优势、原理及参数解析线程池解决了两个不同的问题:1. 减少线程创建的开销,能提高执行大量异步任务的效率2. 提供了一种限制和管理资源及线程的方法,并且还维护了一些基本的统计信息(如已完成的任务数)线程池的使用对`new Thread()`的优势: 1. 复用存在的线程,减少对象创建、消亡的开销,性能佳。 2. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。 3. 提供定时执行、定期执行、单线程、并发数控制等功能。

线程池

线程池解决了两个不同的问题:

  1. 减少线程创建的开销,能提高执行大量异步任务的效率
  2. 提供了一种限制和管理资源及线程的方法,并且还维护了一些基本的统计信息(如已完成的任务数)

线程池的使用对new Thread()的优势:

  1. 复用存在的线程,减少对象创建、消亡的开销,性能佳。
  2. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
  3. 提供定时执行、定期执行、单线程、并发数控制等功能。

ThreadPoolExecutor

常用默认实现:

  1. Executors#newCachedThreadPool:无边界线程池,带有自动线程回收
  2. Executors#newFixedThreadPool:固定大小的线程池
  3. Executors#newSingleThreadExecutor:单个后台线程,大多数场景用于预初始化配置

有需要执行的任务进入线程池时

  • 当前线程数小于核心线程数时,创建线程。
  • 当前线程数大于等于核心线程数,且工作队列未满时,将任务放入工作队列。
  • 当前线程数大于等于核心线程数,且工作队列已满
    • 若线程数小于最大线程数,创建线程
    • 若线程数等于最大线程数,抛出异常,拒绝任务(具体处理方式取决于handler的策略)

主要参数

  • corePoolSize
    核心线程数。空闲时仍会保留在池中的线程数,除非设置了allowCoreThreadTimeOut参数

  • maximumPoolSize
    最大线程数。允许在池中的最大线程数

  • keepAliveTime
    存活时间。当前线程数大于核心线程数时,空余线程的最长存活时间

  • unit
    单位。keepAliveTime参数的时间单位

  • workQueue
    工作队列,接口类为阻塞队列。任务执行前存储的队列,只有通过submit方法提交的任务才会进入队列

  • threadFactory
    线程工厂。创建线程。默认使用Executors.defaultThreadFactory(),所有的线程都属于同一个ThreadGroup,都有相同的优先级,且均不是守护线程。
    (可用new NamedThreadFactory("test")来对线程池中的线程添加前缀标识)

  • handler
    任务丢弃策略。若线程池已经关闭、或线程池已满,那么新的任务会被拒绝。

    • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
      • ThreadPoolExecutor.DiscardPolicy:丢弃任务,但不抛出异常。
        • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(循环此过程)
        • ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

BlockingQueue

BlockingQueue类型

  • ArrayBlockingQueue:由数组结构组成的有界阻塞队列
  • LinkedBlockingQueue:由链表结构组成的有界阻塞队列
  • PriorityBlockingQueue:支持优先级排序的无界阻塞队列
  • DealyQueue:使用优先级队列实现的无界阻塞队列
  • SynchronousQueue:不存储元素的阻塞队列
  • LinkedTransferQueue:由链表结构组成的无界阻塞队列
  • LinkedBlockingDeque:由链表结构组成的双向阻塞队列

ArrayBlockingQueue

ArrayBlockingQueue是定长阻塞队列。原理是使用一个可重入锁和Condition进行并发控制(classic two-condition algorithm)。


参考资料:

  1. 精通ThreadPoolExcutor
  2. Java并发编程中四种线程池
相关文章
|
2月前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
2月前
|
Prometheus 监控 Cloud Native
JAVA线程池监控以及动态调整线程池
【10月更文挑战第22天】在 Java 中,线程池的监控和动态调整是非常重要的,它可以帮助我们更好地管理系统资源,提高应用的性能和稳定性。
190 64
|
1月前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
28天前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####
|
2月前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
119 38
|
2月前
|
存储 缓存 监控
Java中的线程池深度解析####
本文深入探讨了Java并发编程中的核心组件——线程池,从其基本概念、工作原理、核心参数解析到应用场景与最佳实践,全方位剖析了线程池在提升应用性能、资源管理和任务调度方面的重要作用。通过实例演示和性能对比,揭示合理配置线程池对于构建高效Java应用的关键意义。 ####
|
2月前
|
存储 Java 开发者
Java 中 Set 类型的使用方法
【10月更文挑战第30天】Java中的`Set`类型提供了丰富的操作方法来处理不重复的元素集合,开发者可以根据具体的需求选择合适的`Set`实现类,并灵活运用各种方法来实现对集合的操作和处理。
|
2月前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
84 2
|
2月前
|
存储 Java 编译器
Java泛型类型擦除以及类型擦除带来的问题
泛型擦除是指Java编译器在编译期间会移除所有泛型信息,使所有泛型类型在运行时都变为原始类型。例如,`List<String>` 和 `List<Integer>` 在JVM中都视为 `List`。因此,通过 `getClass()` 比较两个不同泛型类型的 `ArrayList` 实例会返回 `true`。此外,通过反射调用 `add` 方法可以向 `ArrayList<Integer>` 中添加字符串,进一步证明了泛型信息在运行时被擦除。
49 2
|
2月前
|
Prometheus 监控 Cloud Native
在 Java 中,如何使用线程池监控以及动态调整线程池?
【10月更文挑战第22天】线程池的监控和动态调整是一项重要的任务,需要我们结合具体的应用场景和需求,选择合适的方法和策略,以确保线程池始终处于最优状态,提高系统的性能和稳定性。
340 2