【Java 并发编程】线程池机制 ( ThreadPoolExecutor 线程池构造参数分析 | 核心线程数 | 最大线程数 | 非核心线程存活时间 | 任务阻塞队列 )

简介: 【Java 并发编程】线程池机制 ( ThreadPoolExecutor 线程池构造参数分析 | 核心线程数 | 最大线程数 | 非核心线程存活时间 | 任务阻塞队列 )

文章目录

前言

一、ThreadPoolExecutor 构造参数

二、newCachedThreadPool 参数分析

三、newFixedThreadPool 参数分析

四、newSingleThreadExecutor 参数分析

前言

在上一篇博客 【Java 并发编程】线程池机制 ( 线程池示例 | newCachedThreadPool | newFixedThreadPool | newSingleThreadExecutor ) 使用了 3 33 种类型的线程池 , 3 33 种线程池都使用了 ThreadPoolExecutor , 该类时线程池的核心 ;


本篇博客中分析这 3 33 种线程池 ;






一、ThreadPoolExecutor 构造参数


ThreadPoolExecutor 是线程池中最核心的类 , 其构造函数如下 :


 

public ThreadPoolExecutor(int corePoolSize,     // 核心线程数 , 这些线程基本不会被销毁
                              int maximumPoolSize,      // 最大线程数 , 线程池能创建的最大线程数量
                              long keepAliveTime,     // 空闲情况下 , 非核心线程存活时间
                              TimeUnit unit,      // 空闲时间单位
                              BlockingQueue<Runnable> workQueue,// 任务的阻塞队列
                              ThreadFactory threadFactory,    // 创建线程的工厂类
                              RejectedExecutionHandler handler) // 拒绝策略


int corePoolSize 核心线程数 , 这些线程基本不会被销毁 ;


int maximumPoolSize 最大线程数 , 线程池能创建的最大线程数量 , 包括 核心线程 + 非核心线程 ;


long keepAliveTime 空闲情况下 , 非核心线程存活时间 ;


TimeUnit unit 空闲时间单位 ;


BlockingQueue<Runnable> workQueue 任务的阻塞队列 , 任务设置到线程池后 , 在该队列中排队等待执行 ;


ThreadFactory threadFactory 创建线程的工厂类 ;


RejectedExecutionHandler handler 拒绝策略 , 如果线程池已满 , 如果再放入新的任务后的拒绝策略






二、newCachedThreadPool 参数分析


ExecutorService executorService1 = Executors.newCachedThreadPool(); 创建线程池代码如下 :


 

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


分析上述代码中 ThreadPoolExecutor 构造函数参数 :


核心线程数 0 00 , 没有核心线程 ;


最大线程数 Integer.MAX_VALUE , 值为 2 31 − 1 2^{31} - 12

31

−1 , 这些线程都是非核心线程 , 是无限大的 ; 注意这里有 OOM 风险 ;


线程的存活时间 60 6060 秒 ;


使用的等待队列是 SynchronousQueue<Runnable> 队列 ;



SynchronousQueue 队列不存储元素 , 后一个 Runnable 任务入队 , 必须等到前一个任务执行完毕才可以 , 否则会一直阻塞等待 ;



使用该线程池 , 如果执行 100000 100000100000 个 Runnable 任务 , 则会创建 100000 100000100000 个线程 , 与 【Java 并发编程】线程池机制 ( 测试线程开销 | 启动线程分析 | 用户态 | 内核态 | 用户线程 | 内核线程 | 轻量级进程 ) 一、测试线程开销 1、正常测试 章节测试 ;


首次创建 100000 100000100000 线程 , 性能基本相同 , 只是添加了一个线程存活时间 ;

如果再次创建 100000 100000100000 线程 , 此时线程池中的线程如果执行完毕 , 可以复用之前创建的 100000 100000100000 线程池 , 不用重新创建线程 ; 前提是期间没有间断 , 如果线程间断超过了 " 非工作线程存活时间 " , 这些线程就会被销毁 ;





三、newFixedThreadPool 参数分析


ExecutorService executorService2 = Executors.newFixedThreadPool(10); 创建线程池代码如下 :


public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }


分析上述代码中 ThreadPoolExecutor 构造函数参数 :


核心线程数是 nThreads , 这是传入的参数 ;


最大线程数 nThreads , 核心线程数是 nThreads , 所有的线程都是核心线程 ;


非核心线程的存活时间 0 00 毫秒 ; 由于所有线程都是核心线程 , 设置非核心线程存货事件意义不大 ;


使用的等待队列是 LinkedBlockingQueue<Runnable> 队列 ;



LinkedBlockingQueue 队列是基于链表的阻塞队列 , 该队列吞吐量高于 ArrayBlockingQueue 队列 , 低于 SynchronousQueue 队列 ;



假设核心线程数为 10 1010 , 有 100 100100 个任务需要执行 ;


执行 100 100100 个 Runnable 任务 , 如果 10 1010 个核心线程没有满 , 则将任务提交给核心线程执行 ; 如果核心线程都满了 , 则将 Runnable 任务放到 LinkedBlockingQueue<Runnable> 等待队列 , 假如该等待队列中任务也满了 , 则需要执行 RejectedExecutionHandler handler 拒绝策略 ;


该拒绝策略默认是 defaultHandler ;


 

private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();






四、newSingleThreadExecutor 参数分析


ExecutorService executorService3 = Executors.newSingleThreadExecutor(); 创建线程池代码如下 :


 

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }


分析上述代码中 ThreadPoolExecutor 构造函数参数 :


核心线程数是 1 11 , 只有 1 11 个核心线程 ;


最大线程数 1 11 , 核心线程数是 1 11 , 所有的线程都是核心线程 ;


非核心线程的存活时间 0 00 毫秒 ; 由于所有线程都是核心线程 , 设置非核心线程存货事件意义不大 ;


使用的等待队列是 LinkedBlockingQueue<Runnable> 队列 ;



LinkedBlockingQueue 队列是基于链表的阻塞队列 , 该队列吞吐量高于 ArrayBlockingQueue 队列 , 低于 SynchronousQueue 队列 ;



整个线程池只有 1 11 个核心线程在工作 ; 100 100100 个任务在 LinkedBlockingQueue<Runnable> 任务队列中排队等待执行 ;


目录
相关文章
|
1天前
|
数据采集
多线程在编程中的重要性有什么?并以LabVIEW为例进行说明
多线程在编程中的重要性有什么?并以LabVIEW为例进行说明
11 4
|
1天前
|
安全 Java 调度
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第12天】 在现代软件开发中,多线程编程是提升应用程序性能和响应能力的关键手段之一。特别是在Java语言中,由于其内置的跨平台线程支持,开发者可以轻松地创建和管理线程。然而,随之而来的并发问题也不容小觑。本文将探讨Java并发编程的核心概念,包括线程安全策略、锁机制以及性能优化技巧。通过实例分析与性能比较,我们旨在为读者提供一套既确保线程安全又兼顾性能的编程指导。
|
2天前
|
安全 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第11天】在Java并发编程中,线程安全和性能优化是两个重要的主题。本文将深入探讨这两个方面,包括线程安全的基本概念,如何实现线程安全,以及如何在保证线程安全的同时进行性能优化。我们将通过实例和代码片段来说明这些概念和技术。
3 0
|
2天前
|
Java 调度
Java并发编程:深入理解线程池
【5月更文挑战第11天】本文将深入探讨Java中的线程池,包括其基本概念、工作原理以及如何使用。我们将通过实例来解释线程池的优点,如提高性能和资源利用率,以及如何避免常见的并发问题。我们还将讨论Java中线程池的实现,包括Executor框架和ThreadPoolExecutor类,并展示如何创建和管理线程池。最后,我们将讨论线程池的一些高级特性,如任务调度、线程优先级和异常处理。
|
4天前
|
Java
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
12 1
|
6天前
|
消息中间件 监控 前端开发
面试官:核心线程数为0时,线程池如何执行?
线程池是 Java 中用于提升程序执行效率的主要手段,也是并发编程中的核心实现技术,并且它也被广泛的应用在日常项目的开发之中。那问题来了,如果把线程池中的核心线程数设置为 0 时,线程池是如何执行的? 要回答这个问题,我们首先要了解在正常情况下,线程池的执行流程,也就是说当有一个任务来了之后,线程池是如何运行的? ## 1.线程池的执行流程 正常情况下(核心线程数不为 0 的情况下)线程池的执行流程如下: 1. **判断核心线程数**:先判断当前工作线程数是否大于核心线程数,如果结果为 false,则新建线程并执行任务。 2. **判断任务队列**:如果大于核心线程数,则判断任务队列是否
15 1
面试官:核心线程数为0时,线程池如何执行?
|
6天前
|
安全 Java 开发者
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第7天】在Java中,多线程编程是提高应用程序性能和响应能力的关键。本文将深入探讨Java并发编程的核心概念,包括线程安全、同步机制以及性能优化策略。我们将通过实例分析,了解如何避免常见的并发问题,如死锁、竞态条件和资源争用,并学习如何使用Java提供的并发工具来构建高效、可靠的多线程应用。
|
6天前
|
缓存 Java
Java并发编程:深入理解线程池
【5月更文挑战第7天】本文将深入探讨Java并发编程中的重要概念——线程池。我们将了解线程池的基本概念,以及如何使用Java的Executor框架来创建和管理线程池。此外,我们还将讨论线程池的优点和缺点,以及如何选择合适的线程池大小。最后,我们将通过一个示例来演示如何使用线程池来提高程序的性能。
|
12天前
|
存储 安全 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第1天】本文将深入探讨Java并发编程的核心概念,包括线程安全和性能优化。我们将详细分析线程安全问题的根源,以及如何通过合理的设计和编码实践来避免常见的并发问题。同时,我们还将探讨如何在保证线程安全的前提下,提高程序的并发性能,包括使用高效的同步机制、减少锁的竞争以及利用现代硬件的并行能力等技术手段。
|
1天前
|
Java 调度
Java一分钟之线程池:ExecutorService与Future
【5月更文挑战第12天】Java并发编程中,`ExecutorService`和`Future`是关键组件,简化多线程并提供异步执行能力。`ExecutorService`是线程池接口,用于提交任务到线程池,如`ThreadPoolExecutor`和`ScheduledThreadPoolExecutor`。通过`submit()`提交任务并返回`Future`对象,可检查任务状态、获取结果或取消任务。注意处理`ExecutionException`和避免无限等待。实战示例展示了如何异步执行任务并获取结果。理解这些概念对提升并发性能至关重要。
15 5