【Java 并发编程】线程池机制 ( 线程池阻塞队列 | 线程池拒绝策略 | 使用 ThreadPoolExecutor 自定义线程池参数 )

简介: 【Java 并发编程】线程池机制 ( 线程池阻塞队列 | 线程池拒绝策略 | 使用 ThreadPoolExecutor 自定义线程池参数 )

文章目录

一、线程池阻塞队列

二、拒绝策略

三、使用 ThreadPoolExecutor 自定义线程池参数





一、线程池阻塞队列


线程池阻塞队列是线程池创建的第 5 55 个参数 : BlockingQueue<Runnable> workQueue ;


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


线程池阻塞队列 : 线程池中的阻塞队列 , 同一时刻 , 只能有 1 11 个线程访问队列 , 执行任务 入队 / 出队 操作 ; 队列都是 FIFO 先进先出 ;


阻塞队列相关概念 :


大小边界 :

有界 : 阻塞队列 大小有限制 , 不是无限大的 ;

无界 : 阻塞队列 理论上无限大 , 比如设置成 Integer.MAX_VALUE ;

队列已满 : 只能出队 , 不能入队 ; 入队操作需阻塞等待 ;

队列为空 : 只能入队 , 不能出队 ; 出队操作需要等待 ;

ArrayBlockingQueue : 有界阻塞队列 , 需要 指定阻塞队列大小 ;


LinkedBlockingQueue : 无界阻塞队列 , 基于链表的阻塞队列 ;


Executors.newCachedThreadPool() 或 Executors.newFixedThreadPool(10) 方法创建的线程池 , 使用的是该阻塞队列 ;

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


Executors.newCachedThreadPool() 方法创建的线程池 , 使用的是该阻塞队列 ;

PriorityBlockingQueue : 有优先级的阻塞队列 ;



阻塞队列吞吐量 : SynchronousQueue > LinkedBlockingQueue > ArrayBlockingQueue ;






二、拒绝策略


线程池拒绝策略是线程池创建的第 7 77 个参数 : RejectedExecutionHandler handler ;


 

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



线程池拒绝策略 : 如果核心线程 , 非核心线程都在执行任务 , 阻塞队列是有界的 , 也满了 , 此时线程池如果再添加任务 , 就会触发如下拒绝策略 ;


DiscardPolicy : 丢弃任务 ;

DiscardOldestPolicy : 丢弃队头的最旧的任务 ;

AbortPolicy : 抛出异常 , 这也是默认方式 ;

CallerRunsPolicy : 调用者自行处理 ;


线程池默认的拒绝策略是 抛出异常 方式 ;


 

private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();






三、使用 ThreadPoolExecutor 自定义线程池参数


创建 1 11 个线程池 , 核心线程数是 2 22 , 最大线程数是 3 33 , 则非核心线程 0 ~ 1 个 , 非核心线程最大空闲存活时间 60 秒 , 阻塞队列最大存放 10 个元素 , 拒绝策略设置为抛出异常方式 , 如果阻塞队列装满 , 再次尝试执行新任务时 , 会抛出异常 ;



代码示例 :


import java.util.concurrent.*;
public class Main {
    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(
                2,                          // 核心线程数 2
                3,                      // 最大线程数 3, 非核心线程 0 ~ 1 个
                60,                        // 非核心线程最大空闲存活时间 60 秒
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10),   // 阻塞队列, 最大存放 10 个元素
                Executors.defaultThreadFactory(),       // 线程工厂
                new ThreadPoolExecutor.AbortPolicy()    // 决绝策略, 如果执行任务失败, 抛出异常
        );
        for (int i = 0; i < 20; i ++) {
            executorService.execute(new Task(i));
        }
    }
    static class Task implements Runnable {
        /**
         * 记录线程的索引 0 ~ 99
         */
        private int i = 0;
        public Task(int i) {
            this.i = i;
        }
        @Override
        public void run() {
            System.out.println("线程 ID : " + Thread.currentThread().getName() + " , 线程索引 : " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


执行结果 : 这里线程最大执行到了 12 1212 , 也就是从 0 00 开始计数 , 执行了 13 1313 个任务 , 其中 3 33 个线程池各自执行一个任务 , 阻塞队列存放 10 1010 个任务 , 再次尝试将第 14 1414 个任务放入阻塞队列时 , 报出 java.util.concurrent.RejectedExecutionException 异常 , 但是队列中的 10 1010 个任务也正常执行完毕 ;


线程 ID : pool-1-thread-2 , 线程索引 : 1
线程 ID : pool-1-thread-3 , 线程索引 : 12
线程 ID : pool-1-thread-1 , 线程索引 : 0
Exception in thread "main" java.util.concurrent.RejectedExecutionException: 
Task Main$Task@5cad8086 rejected from java.util.concurrent.ThreadPoolExecutor@6e0be858
[Running, pool size = 3, active threads = 3, queued tasks = 10, completed tasks = 0]
  at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
  at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
  at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
  at Main.main(Main.java:16)
线程 ID : pool-1-thread-3 , 线程索引 : 2
线程 ID : pool-1-thread-1 , 线程索引 : 4
线程 ID : pool-1-thread-2 , 线程索引 : 3
线程 ID : pool-1-thread-1 , 线程索引 : 5
线程 ID : pool-1-thread-2 , 线程索引 : 7
线程 ID : pool-1-thread-3 , 线程索引 : 6
线程 ID : pool-1-thread-1 , 线程索引 : 9
线程 ID : pool-1-thread-2 , 线程索引 : 8
线程 ID : pool-1-thread-3 , 线程索引 : 10
线程 ID : pool-1-thread-2 , 线程索引 : 11

image.png

目录
相关文章
|
19天前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
25 0
|
15天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
15天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
40 3
|
16天前
|
Java 程序员
深入理解Java异常处理机制
Java的异常处理是编程中的一块基石,它不仅保障了代码的健壮性,还提升了程序的可读性和可维护性。本文将深入浅出地探讨Java异常处理的核心概念、分类、处理策略以及最佳实践,旨在帮助读者建立正确的异常处理观念,提升编程效率和质量。
|
17天前
|
Java 开发者 UED
深入探索Java中的异常处理机制##
本文将带你深入了解Java语言中的异常处理机制,包括异常的分类、异常的捕获与处理、自定义异常的创建以及最佳实践。通过具体实例和代码演示,帮助你更好地理解和运用Java中的异常处理,提高程序的健壮性和可维护性。 ##
42 2
|
17天前
|
Java 开发者
Java中的异常处理机制深度剖析####
本文深入探讨了Java语言中异常处理的重要性、核心机制及其在实际编程中的应用策略,旨在帮助开发者更有效地编写健壮的代码。通过实例分析,揭示了try-catch-finally结构的最佳实践,以及如何利用自定义异常提升程序的可读性和维护性。此外,还简要介绍了Java 7引入的多异常捕获特性,为读者提供了一个全面而实用的异常处理指南。 ####
39 2
|
19天前
|
算法 调度 开发者
多线程编程核心:上下文切换深度解析
在多线程编程中,上下文切换是一个至关重要的概念,它直接影响到程序的性能和响应速度。本文将深入探讨上下文切换的含义、原因、影响以及如何优化,帮助你在工作和学习中更好地理解和应用多线程技术。
30 4
|
18天前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
15天前
|
Java API 开发者
深入理解Java中的异常处理机制
本文探讨了Java编程语言中异常处理的核心概念,包括异常类型、异常捕获与抛出、以及最佳实践。通过分析常见的异常场景和处理策略,旨在帮助开发者更好地理解和运用异常处理机制,提高代码的健壮性和可维护性。文章不仅涵盖了基本的try-catch结构,还深入讨论了自定义异常的创建与使用,以及finally块的重要性和应用。此外,还将介绍一些高级技巧,如多异常捕获和嵌套异常处理,为读者提供全面的技术指导。
66 0
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
58 1
C++ 多线程之初识多线程
下一篇
DataWorks