35.Java线程池(线程池概述、线程池的架构、线程池的种类与创建、线程池的底层原理、线程池的工作流程、线程池的拒绝策略、自定义线程池)

news2025/4/15 22:37:42

一、线程池概述

1、线程池的优势
  • 线程池是一种线程使用模式,线程过多会带来调度开销,进而影响缓存局部性和整体性能,而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务,这避免了在处理短时间任务时创建与销毁线程的代价,线程池不仅能够保证内核的充分利用,还能防止过分调度

  • 线程池的工作主要是控制运行的线程数量,在处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行

2、线程池的特点
  • 降低资源消耗: 通过重复利用已创建的线程降低线程创建和销毁造成的销耗

  • 提高响应速度: 当任务到达时,任务可以不需要等待线程创建就能立即执行

  • 提高线程的可管理性: 线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控


二、线程池的架构

  • Java 中的线程池是通过 Executor 框架实现的,该框架中用到了 Executor 接口,Executors 类,ExecutorService 类,ThreadPoolExecutor 类

三、线程池的种类与创建

1、一池 N 线程
(1)基本介绍
  • 线程池中的线程处于一定的量,可以很好的控制线程的并发量

  • 线程可以重复被使用,在显示关闭之前,都将一直存在

  • 超出一定量的线程被提交时候需在队列中等待

(2)创建方式
ExecutorService threadPool = Executors.newFixedThreadPool(5);
(3)适用场景
  • 适用于可以预测线程数量的业务,或者服务器负载较重,对线程数有严格限制的场景
(4)基本使用
  • 使用 5 个窗口处理 10 个顾客请求
ExecutorService threadPool = Executors.newFixedThreadPool(5);

try {
    for (int i = 1; i <= 10; i++) {

        // 执行线程
        threadPool.execute(() -> {
            System.out.println(Thread.currentThread().getName()+" 办理业务");
        });
    }
} catch (Exception e) {
    e.printStackTrace();
} finally {

    // 关闭线程
    threadPool.shutdown();
}
  • 结果
pool-1-thread-1 办理业务
pool-1-thread-5 办理业务
pool-1-thread-4 办理业务
pool-1-thread-3 办理业务
pool-1-thread-2 办理业务
pool-1-thread-3 办理业务
pool-1-thread-4 办理业务
pool-1-thread-5 办理业务
pool-1-thread-1 办理业务
pool-1-thread-2 办理业务
2、一池一线程
(1)基本介绍
  • 线程池中最多执行一个线程,之后提交的线程活动将会排在队列中依次执行
(2)创建方式
ExecutorService threadPool = Executors.newSingleThreadExecutor();
(3)适用场景
  • 适用于需要保证顺序执行各个任务,并且在任意时间点,不会同时有多个线程的场景
(4)基本使用
  • 使用 1 个窗口处理 10 个顾客请求
ExecutorService threadPool = Executors.newSingleThreadExecutor();

try {
    for (int i = 1; i <= 10; i++) {

        // 执行线程
        threadPool.execute(() -> {
            System.out.println(Thread.currentThread().getName()+" 办理业务");
        });
    }
} catch (Exception e) {
    e.printStackTrace();
} finally {

    // 关闭线程
    threadPool.shutdown();
}
  • 结果
pool-1-thread-1 办理业务
pool-1-thread-1 办理业务
pool-1-thread-1 办理业务
pool-1-thread-1 办理业务
pool-1-thread-1 办理业务
pool-1-thread-1 办理业务
pool-1-thread-1 办理业务
pool-1-thread-1 办理业务
pool-1-thread-1 办理业务
pool-1-thread-1 办理业务
3、一池可扩容线程
(1)基本介绍
  • 线程池中数量没有固定,可达到最大值为 Interger. MAX_VALUE

  • 线程池中的线程可进行缓存重复利用和回收,默认回收时间为一分钟

  • 当线程池中没有可用线程时,会重新创建一个线程

(2)创建方式
ExecutorService threadPool = Executors.newCachedThreadPool();
(3)适用场景
  • 适用于创建一个可无限扩大的线程池,服务器负载压力较轻,执行时间较短,任务多的场景
(4)基本使用
  • 处理 20 个顾客请求
ExecutorService threadPool = Executors.newCachedThreadPool();

try {
    for (int i = 1; i <= 20; i++) {

        // 执行线程
        threadPool.execute(() -> {
            System.out.println(Thread.currentThread().getName()+" 办理业务");
        });
    }
} catch (Exception e) {
    e.printStackTrace();
} finally {

    // 关闭线程
    threadPool.shutdown();
}
  • 结果
pool-1-thread-1 办理业务
pool-1-thread-4 办理业务
pool-1-thread-3 办理业务
pool-1-thread-2 办理业务
pool-1-thread-6 办理业务
pool-1-thread-5 办理业务
pool-1-thread-8 办理业务
pool-1-thread-7 办理业务
pool-1-thread-3 办理业务
pool-1-thread-4 办理业务
pool-1-thread-7 办理业务
pool-1-thread-5 办理业务
pool-1-thread-1 办理业务
pool-1-thread-2 办理业务
pool-1-thread-6 办理业务
pool-1-thread-8 办理业务
pool-1-thread-3 办理业务
pool-1-thread-9 办理业务
pool-1-thread-7 办理业务
pool-1-thread-5 办理业务

四、线程池的底层原理

1、ThreadPoolExecutor 类
  • 通过查看上面三种方式创建线程池对象的源代码,发现都有 new ThreadPoolExecutor 操作,具体查看该类的源代码,其构造器涉及七个参数
public ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue<Runnable> workQueue,
                            ThreadFactory threadFactory,
                            RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}
2、ThreadPoolExecutor 构造器涉及的七个参数
  1. int corePoolSize:常驻线程数量

  2. int maximumPoolSize:最大线程数量

  3. long keepAliveTime:空闲线程存活时间

  4. TimeUnit unit:空闲线程存时间单位

  5. BlockingQueue workQueue:阻塞队列,存放提交但未执行任务

  6. ThreadFactory threadFactory:线程工厂,用于创建线程(可省略)

  7. RejectedExecutionHandler handler:阻塞队列满时的拒绝策略(可省略)


五、线程池的工作流程

  • 在创建了线程池后,线程池中的线程数为零

  • 当调用 execute 方法添加一个请求任务时,线程池会做如下判断

    1. 如果正在运行的线程数量小于 corePool 的线程数量,那么马上创建线程运行这个任务

    2. 如果正在运行的线程数量大于或等于 corePool 的线程数量,那么将这个任务存入阻塞队列

    3. 如果这个时候队列已满且正在运行的线程数量小于 maximumPool 的线程数量,则创建非核心线程立刻运行这个任务

    4. 如果队列已满且正在运行的线程数量大于或等于 maximumPool 的线程数量,那么线程池会启动拒绝策略

  • 当一个线程完成任务时,它会从队列中取下一个任务来执行

  • 当一个线程空闲超过一定的时间时,会做如下判断

    1. 如果当前运行的线程数大于 corePool 的线程数量,那么这个线程就被停掉

    2. 线程池的所有任务完成后,最终会收缩到 corePool 的大小


六、线程池的拒绝策略

1、 AbortPolicy
  • 默认的拒绝策略,会直接抛出 RejectedExecutionException 异常阻止系统正常运行
2、DiscardPolicy
  • 该策略会丢弃无法处理的任务,不给予任何处理也不抛出异常,如果允许任务丢失,这是最好的一种策略
3、DiscardOldestPolicy
  • 丢弃队列中等待最久的任务,然后把当前任务存入队列中,并尝试提交当前任务
4、CallerRunsPolicy
  • 该策略既不会丢弃任务,也不会抛出异常,而是将任务退回给调用者

七、自定义线程池

1、Executors 返回的线程池对象的弊端
  • FixedThreadPool 和 SingleThreadExecutor 允许请求队列的长度为 Interger.MAX_VALUE,可能会堆积大量异常, 从而导致 OOM

  • CachedThreadPool 允许的创建线程数量为 Interger.MAX_VALUE,可能会创建大量线程,从而导致 OOM

2、具体实现
package com.my.pool;

import java.util.concurrent.*;

public class MyThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                2L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardOldestPolicy());

        // 处理 10 个顾客请求
        try {
            for (int i = 1; i <= 10; i++) {

                // 执行线程
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName()+" 办理业务");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            // 关闭线程
            threadPool.shutdown();
        }
    }
}
  • 结果
pool-1-thread-1 办理业务
pool-1-thread-4 办理业务
pool-1-thread-3 办理业务
pool-1-thread-2 办理业务
pool-1-thread-3 办理业务
pool-1-thread-4 办理业务
pool-1-thread-1 办理业务
pool-1-thread-5 办理业务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2334633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kubernetes nodeName Manual Scheduling practice (K8S节点名称绑定以及手工调度)

Manual Scheduling 在 Kubernetes 中&#xff0c;手动调度框架允许您将 Pod 分配到特定节点&#xff0c;而无需依赖默认调度器。这对于测试、调试或处理特定工作负载非常有用。您可以通过在 Pod 的规范中设置 nodeName 字段来实现手动调度。以下是一个示例&#xff1a; apiVe…

React 获得dom节点和组件通信

通过REF 实例对象的.current属性获得绑定的DOM节点 组件通信 组件通信 1 父传子 父组件传递数据 子组件接受数据 通过pros对象接受 子组件的形参列表props只读 props中数据不可修改 特殊情况 在子传父的过程中没有直接给子组件添加属性&#xff0c;而是向父组件中添加其他…

代码,Java Maven项目打包遇到的环境问题

这几天在写一些Java版本的Langchain4J的 AI 测试case&#xff0c;有一段时间不运行的Java环境&#xff0c;反复出现环境问题&#xff0c;记录下 1、Java编译版本的问题 修改编译版本&#xff1a; 2、在IDE中运行遇到Maven中JDK版本问题 在ide中执行maven命令&#xff0c;遇到下…

fisco-bcos 关于服务bash status.sh启动runing 中但是5002端口监听不到,出错的问题

bash status.sh Server com.webank.webase.front.Application Port 5002 is running PID(4587) yjmyjm-VMware-Virtual-Platform:~/webase-front$ sudo netstat -anlp | grep 5002 没有端口信息输出 此时可以查看log文件夹下的WeBASE-front.log&#xff0c;找到报错信息如下…

linux多线(进)程编程——(5)虚拟内存与内存映射

前言&#xff08;前情回顾&#xff09; 进程君开发了管道这门技术后&#xff0c;修真界的各种沟通越来越频繁&#xff0c;这天进程君正与自己的孩子沟通&#xff0c;进程君的孩子说道&#xff1a; “爸爸&#xff0c;昨天我看他们斗法&#xff0c;小明一拳打到了小刚的肚子上&…

SpringBoot 动态路由菜单 权限系统开发 菜单权限 数据库设计 不同角色对应不同权限

介绍 系统中的路由配置可以根据用户的身份、角色或其他权限信息动态生成&#xff0c;而不是固定在系统中。不同的用户根据其权限会看到不同的路由&#xff0c;访问不同的页面。对应各部门不同的权限。 效果 [{"id": 1,"menuName": "用户管理"…

[dp8_子数组] 乘积为正数的最长子数组长度 | 等差数列划分 | 最长湍流子数组

目录 1.乘积为正数的最长子数组长度 2.等差数列划分 3.最长湍流子数组 写代码做到&#xff0c;只用维护好自己的一小步 1.乘积为正数的最长子数组长度 链接&#xff1a;1567. 乘积为正数的最长子数组长度 给你一个整数数组 nums &#xff0c;请你求出乘积为正数的最长子数…

【图像处理基石】什么是通透感?

一、画面的通透感定义 画面的通透感指图像在色彩鲜明度、空间层次感、物体轮廓清晰度三方面的综合表现&#xff0c;具体表现为&#xff1a; 色彩鲜明&#xff1a;颜色纯净且饱和度适中&#xff0c;无灰暗或浑浊感&#xff1b;层次分明&#xff1a;明暗过渡自然&#xff0c;光…

无锡无人机超视距驾驶证怎么考?

无锡无人机超视距驾驶证怎么考&#xff1f;在近年来&#xff0c;无人机技术的迅猛发展使得无人机的应用场景变得愈发广泛&#xff0c;其不仅在环境监测、农业喷洒、快递配送等领域展现出真金白银的价值&#xff0c;同时也推动了无人机驾驶证的需求。尤其是在无锡&#xff0c;随…

213、【图论】有向图的完全联通(Python)

题目描述 原题链接&#xff1a;105. 有向图的完全联通 代码实现 import collectionsn, k list(map(int, input().split())) adjacency collections.defaultdict(list) for _ in range(k):head, tail list(map(int, input().split()))adjacency[head].append(tail)visited_…

图像形态学操作对比(Opencv)

形态学基于图像的形状进行操作&#xff0c;用于处理二值化图像&#xff0c;主要包括腐蚀和膨胀两种基本操作。这些操作通常用于去除噪声、分隔或连接相邻的元素以及寻找图像中显著的最大点和最小点。 1. 形态学操作 import cv2 import numpy as np import matplotlib.pyplot …

复刻系列-星穹铁道 3.2 版本先行展示页

复刻星穹铁道 3.2 版本先行展示页 0. 视频 手搓&#xff5e;星穹铁道&#xff5e;展示页&#xff5e;&#xff5e;&#xff5e; 1. 基本信息 作者: 啊是特嗷桃系列: 复刻系列官方的网站: 《崩坏&#xff1a;星穹铁道》3.2版本「走过安眠地的花丛」专题展示页现已上线复刻的网…

Linux:进程理解1(查看进程,创造进程,进程状态)

进程理解 &#xff08;一&#xff09;查看进程通过系统调用获取进程标示* &#xff08;二&#xff09;创造进程&#xff08;fork&#xff09;1. 创造的子进程的PCB代码数据怎么来&#xff1f;2.一个函数为什么有两个返回值&#xff1f;3. 为什么这里会有 两个 id值&#xff1f;…

异形遮罩之QML中的 `OpacityMask` 实战

文章目录 &#x1f327;️ 传统实现的问题&#x1f449; 效果图 &#x1f308; 使用 OpacityMask 的理想方案&#x1f449;代码如下&#x1f3af; 最终效果&#xff1a; ✨ 延伸应用&#x1f9e0; 总结 在 UI 设计中&#xff0c;经常希望实现一些“异形区域”拥有统一透明度或颜…

如何为您的设计应用选择高速连接器

电气应用的设计过程需要考虑诸多因素&#xff0c;尤其是在设计高速网络时。许多连接器用户可能没有意识到&#xff0c;除了在两个互连之间组装导电线路之外&#xff0c;还需要考虑各种工艺。在建立高速连接并确保适当的信号完整性时&#xff0c;必须考虑蚀刻、公差、屏蔽等因素…

【论文阅读】UniAD: Planning-oriented Autonomous Driving

一、Introduction 传统的无人驾驶采用了区分子模块的设计&#xff0c;即将无人驾驶拆分为感知规划控制三个模块&#xff0c;这虽然能够让无人驾驶以一个很清晰的结构实现&#xff0c;但是感知的结果在传达到规划部分的时候&#xff0c;会导致部分信息丢失&#xff0c;这势必会…

upload-labs二次打

1(前端js绕过) 弹窗&#xff0c;先看看有没有js有&#xff0c;禁用js 禁用后就可以上传php文件了&#xff0c;然后我们就去访问文件&#xff0c;成功 2&#xff08;MIME绕过&#xff09; 先上传一个php文件试试&#xff0c;不行&#xff0c;.htaccess不行, 试试MIME类型&am…

提权实战!

就是提升权限&#xff0c;当我们拿到一个shell权限较低&#xff0c;当满足MySQL提权的要求时&#xff0c;就可以进行这个提权。 MySQL数据库提权&#xff08;Privilege Escalation&#xff09;是指攻击者通过技术手段&#xff0c;从低权限的数据库用户提升到更高权限&#xff…

ChromeOS 135 版本更新

ChromeOS 135 版本更新 一、ChromeOS 135 更新内容 1. ChromeOS 电池寿命优化策略 为了延长 Chromebook 的使用寿命&#xff0c;ChromeOS 135 引入了一项全新的电池充电限制策略 —— DevicePowerBatteryChargingOptimization&#xff0c;可提供更多充电优化选项&#xff0c…

javaSE.Lambda表达式

如果一个接口中有且只有一个待实现的抽象方法&#xff0c;那么我们可以将匿名内部类简写为Lambda表达式。 简写规则 标准格式&#xff1a; &#xff08;【参数类型 参数名称&#xff0c;】...&#xff09; -> {代码语句&#xff0c; 包括返回值} 只有一行花括号{}可以省略。…