线程池监控

news2025/1/19 20:26:03

如何监控线程池

文章目录

  • 如何监控线程池
    • 线程池两个点需要监控
      • 第一点:线程的变化情况
      • 第二点:任务的变化
    • 用来监控线程变化的方法
      • 自定义一个带监控的线程池,然后继承ThreadPoolExecutor,重载构造方法
    • 自定义线程池中线程的名称的4种方式
      • Spring 框架提供的 CustomizableThreadFactory
      • Google guava工具类 提供的 ThreadFactoryBuilder ,使用链式方法创建。
      • Apache commons-lang3提供的 BasicThreadFactory
      • 自定义ThreadFactory
    • 测试我们的监控线程池的功能
      • 定义Task
      • 编写main方法

线程池两个点需要监控

第一点:线程的变化情况

在这里插入图片描述

第二点:任务的变化

在这里插入图片描述

用来监控线程变化的方法

方法描述监控方面
getActiveCount()获取正在工作的线程数监控线程的变化
getPoolSize()获取当前存在的线程数监控线程的变化
getLargestPoolSize()获取历史最大的线程数监控线程的变化
getTaskCount()获取计划执行的任务总数监控任务的变化
getCompletedTaskCount()获取已完成的任务数监控任务的变化
getQueue()获取任务队列监控任务的变化

自定义一个带监控的线程池,然后继承ThreadPoolExecutor,重载构造方法

package com.kang.mongodb.pool;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.concurrent.*;

/**
 * @Author Emperor Kang
 * @ClassName MonitorThhreadPool
 * @Description TODO
 * @Date 2023/8/7 13:44
 * @Version 1.0
 * @Motto 让营地比你来时更干净
 */
@Slf4j
public class MonitorThreadPool extends ThreadPoolExecutor {
    /**
     * 自定义线程池
     * @param corePoolSize
     * @param maximumPoolSize
     * @param keepAliveTime
     * @param unit
     * @param workQueue
     */
    public MonitorThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public MonitorThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public MonitorThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public MonitorThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    /**
     * 重写before executor方法,该方法每次任务执行前调用,在他内部调用一遍monitor方法,每当有任务执行的时候,输出一次线程池的情况,
     * @param t
     * @param r
     */
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        log.info("beforeExecute");
        monitor();
    }

    /**
     * 接着重写afterexecutor方法,该方法每次任务完成后调用,在它内部也调用一遍monitor方法,每当有任务完成的时候,输出一次线程池的情况,
     * @param r
     * @param t
     */
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        log.info("afterExecute");
        monitor();
    }

    /**
     * 最后重写terminated的方法。该方法在线程池关闭前调用,同样的,在它的内部也调用一遍monitor方法,
     */
    @Override
    protected void terminated() {
        log.info("terminated");
        monitor();
    }

    /**
     * 监控线程池情况
     */
    public void monitor(){
        log.info("正在工作的线程数:{}",getActiveCount());
        log.info("当前存在的线程数:{}",getPoolSize());
        log.info("历史最大的线程数:{}",getLargestPoolSize());
        log.info("已提交的任务总数:{}",getTaskCount());
        log.info("已完成的任务数:{}",getCompletedTaskCount());
        log.info("队列中的任务数:{}",getQueue().size());
        log.info("================线程池华丽分割线================");
    }
}
  • 监控方法monitor
  • 重写beforeExecute方法,该方法每次任务执行前调用,在他内部调用一遍monitor方法,每当有任务执行的时候,输出一次线程池的情况,
  • 接着重写afterExecute方法,该方法每次任务完成后调用,在它内部也调用一遍monitor方法,每当有任务完成的时候,输出一次线程池的情况,
  • 最后重写terminated的方法。该方法在线程池关闭前调用,同样的,在它的内部也调用一遍monitor方法
  • 当线程池关闭前一刻,我们可以了解到线程池最后的情况,至此整个带监控功能的线程池编写完成

自定义线程池中线程的名称的4种方式

Spring 框架提供的 CustomizableThreadFactory

private ThreadFactory springThreadFactory = new CustomizableThreadFactory("springThread-pool-");
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
								10, 
								30, 
								5, 
								TimeUnit.MINUTES, 
								new ArrayBlockingQueue<Runnable>(1000),
								springThreadFactory ); //给线程池中的线程自定义名称

Google guava工具类 提供的 ThreadFactoryBuilder ,使用链式方法创建。

private ThreadFactory guavaThreadFactory = new ThreadFactoryBuilder().setNameFormat("retryClient-pool-").build();
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
								10, 
								30, 
								5, 
								TimeUnit.MINUTES, 
								new ArrayBlockingQueue<Runnable>(1000),
								guavaThreadFactory ); //给线程池中的线程自定义名称

Apache commons-lang3提供的 BasicThreadFactory

private ThreadFactory basicThreadFactory = new BasicThreadFactory.Builder().namingPattern("basicThreadFactory-").build();
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
								10, 
								30, 
								5, 
								TimeUnit.MINUTES, 
								new ArrayBlockingQueue<Runnable>(1000),
								basicThreadFactory ); //给线程池中的线程自定义名称

自定义ThreadFactory

public class NamesThreadFactory implements ThreadFactory{
	
	private final ThreadGroup group;
	private final AtomicInteger threadNumber = new AtomicInteger(1);
	private final String namePrefix;

	public NamesThreadFactory(String name) {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
        if (null == name || name.isEmpty()) {
            name = "pool";
        }
        namePrefix = name + "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }

}

使用方式

private NamesThreadFactory namesThreadFactory = new NamesThreadFactory("namesThread-");
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
								10, 
								30, 
								5, 
								TimeUnit.MINUTES, 
								new ArrayBlockingQueue<Runnable>(1000),
								namesThreadFactory); //给线程池中的线程自定义名称

测试我们的监控线程池的功能

定义Task

package com.kang.mongodb.pool;

import lombok.extern.slf4j.Slf4j;

/**
 * @Author Emperor Kang
 * @ClassName Task
 * @Description 制定一个任务task,实现runnable接口,定义一个int类型的变量timeout,表示任务执行时长,重载构造方法用于初始化timeout,任务内容是使当前线程休眠,以此来模拟任务执行时长。
 * @Date 2023/8/7 14:07
 * @Version 1.0
 * @Motto 让营地比你来时更干净
 */
@Slf4j
public class Task implements Runnable{
    /**
     * 执行时间
     */
    private int timeout;

    public Task(int timeout) {
        this.timeout = timeout;
    }

    @Override
    public void run() {
        try {
            //打印自定义线程名
            log.info("当前线程名称:{}",Thread.currentThread().getName());
            //使当前线程休眠指定时间
            Thread.sleep(timeout * 1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 这里使用了spring的自定义线程名称的方式

编写main方法

  • 接下来使用带监控功能的线程池,执行该任务。首先创建一个带监控功能的限制值,并指定核心线程数为1,最大线程数为三,空闲线程存活时间为0秒,任务队列采用linkedblockingqueue,并指定队列长度为二,接着使用for循环。从5~1提交5个任务,创建任务并指定任务执行时长为I,接着提交任务,每隔500毫秒提交一个,sleep方法有异常抛出使用try—catch将其捕获。
  • 任务提交完以后,我们使主线程休眠6秒钟,这样做的目的在于,想在关闭线程池之前获取一次线程池的情况,最后写上finally代码块,在finally代码块中调用shoudown方法关闭线程池。至此main方法编写完成,
package com.kang.mongodb.pool;

import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
 * @Author Emperor Kang
 * @ClassName MainTest
 * @Description TODO
 * @Date 2023/8/7 14:11
 * @Version 1.0
 * @Motto 让营地比你来时更干净
 */
public class MainTest {
    public static void main(String[] args) {
        // 自定义线程池名称
        ThreadFactory threadFactory = new CustomizableThreadFactory("bigdata-thread-pool-");
        // 创建带监控的线程池
        MonitorThreadPool monitorThreadPool = new MonitorThreadPool(1, 3, 0, TimeUnit.SECONDS, new LinkedBlockingDeque<>(2),threadFactory);
        try {
            // 提交多个任务
            for (int i = 10; i > 0; i--) {
                // 创建任务
                Task task = new Task(i);
                // 提交任务
                monitorThreadPool.submit(task);
                // 每隔500毫秒提交一个
                Thread.sleep(500);
            }
            // 使主线程休眠6秒钟
            Thread.sleep(6000);
            // 关闭线程池之前获取一次线程池情况
            monitorThreadPool.monitor();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池
            monitorThreadPool.shutdown();
        }
    }
}

执行程序观察输出

MonitorThreadPool - beforeExecute
MonitorThreadPool - 正在工作的线程数:1
MonitorThreadPool - 当前存在的线程数:1
MonitorThreadPool - 历史最大的线程数:1
MonitorThreadPool - 已提交的任务总数:1
MonitorThreadPool - 已完成的任务数:0
MonitorThreadPool - 队列中的任务数:0
MonitorThreadPool - ================线程池华丽分割线================
Task - 当前线程名称:bigdata-thread-pool-1
MonitorThreadPool - beforeExecute
MonitorThreadPool - 正在工作的线程数:2
MonitorThreadPool - 当前存在的线程数:2
MonitorThreadPool - 历史最大的线程数:2
MonitorThreadPool - 已提交的任务总数:4
MonitorThreadPool - 已完成的任务数:0
MonitorThreadPool - 队列中的任务数:2
MonitorThreadPool - ================线程池华丽分割线================
Task - 当前线程名称:bigdata-thread-pool-2
MonitorThreadPool - beforeExecute
MonitorThreadPool - 正在工作的线程数:3
MonitorThreadPool - 当前存在的线程数:3
MonitorThreadPool - 历史最大的线程数:3
MonitorThreadPool - 已提交的任务总数:5
MonitorThreadPool - 已完成的任务数:0
MonitorThreadPool - 队列中的任务数:2
MonitorThreadPool - ================线程池华丽分割线================
14:28:24.815 [bigdata-thread-pool-3] INFO com.kang.mongodb.pool.Task - 当前线程名称:bigdata-thread-pool-3
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@14bf9759 rejected from com.kang.mongodb.pool.MonitorThreadPool@553f17c[Running, pool size = 3, active threads = 3, queued tasks = 2, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
	at com.kang.mongodb.pool.MainTest.main(MainTest.java:29)
MonitorThreadPool - afterExecute
MonitorThreadPool - 正在工作的线程数:3
MonitorThreadPool - 当前存在的线程数:3
MonitorThreadPool - 历史最大的线程数:3
MonitorThreadPool - 已提交的任务总数:5
MonitorThreadPool - 已完成的任务数:0
MonitorThreadPool - 队列中的任务数:2
MonitorThreadPool - ================线程池华丽分割线================
MonitorThreadPool - beforeExecute
MonitorThreadPool - 正在工作的线程数:3
MonitorThreadPool - 当前存在的线程数:3
MonitorThreadPool - 历史最大的线程数:3
MonitorThreadPool - 已提交的任务总数:5
MonitorThreadPool - 已完成的任务数:1
MonitorThreadPool - 队列中的任务数:1
MonitorThreadPool - ================线程池华丽分割线================
Task - 当前线程名称:bigdata-thread-pool-3
MonitorThreadPool - afterExecute
MonitorThreadPool - 正在工作的线程数:3
MonitorThreadPool - 当前存在的线程数:3
MonitorThreadPool - 历史最大的线程数:3
MonitorThreadPool - 已提交的任务总数:5
MonitorThreadPool - 已完成的任务数:1
MonitorThreadPool - 队列中的任务数:1
MonitorThreadPool - ================线程池华丽分割线================
MonitorThreadPool - beforeExecute
MonitorThreadPool - 正在工作的线程数:3
MonitorThreadPool - 当前存在的线程数:3
MonitorThreadPool - 历史最大的线程数:3
MonitorThreadPool - 已提交的任务总数:5
MonitorThreadPool - 已完成的任务数:2
MonitorThreadPool - 队列中的任务数:0
MonitorThreadPool - ================线程池华丽分割线================
Task - 当前线程名称:bigdata-thread-pool-2
MonitorThreadPool - afterExecute
MonitorThreadPool - 正在工作的线程数:3
MonitorThreadPool - 当前存在的线程数:3
MonitorThreadPool - 历史最大的线程数:3
MonitorThreadPool - 已提交的任务总数:5
MonitorThreadPool - 已完成的任务数:2
MonitorThreadPool - 队列中的任务数:0
MonitorThreadPool - ================线程池华丽分割线================
MonitorThreadPool - afterExecute
MonitorThreadPool - 正在工作的线程数:2
MonitorThreadPool - 当前存在的线程数:2
MonitorThreadPool - 历史最大的线程数:3
MonitorThreadPool - 已提交的任务总数:5
MonitorThreadPool - 已完成的任务数:3
MonitorThreadPool - 队列中的任务数:0
MonitorThreadPool - ================线程池华丽分割线================
MonitorThreadPool - afterExecute
MonitorThreadPool - 正在工作的线程数:1
MonitorThreadPool - 当前存在的线程数:1
MonitorThreadPool - 历史最大的线程数:3
MonitorThreadPool - 已提交的任务总数:5
MonitorThreadPool - 已完成的任务数:4
MonitorThreadPool - 队列中的任务数:0
MonitorThreadPool - ================线程池华丽分割线================
MonitorThreadPool - terminated
MonitorThreadPool - 正在工作的线程数:0
MonitorThreadPool - 当前存在的线程数:0
MonitorThreadPool - 历史最大的线程数:3
MonitorThreadPool - 已提交的任务总数:5
MonitorThreadPool - 已完成的任务数:5
MonitorThreadPool - 队列中的任务数:0
MonitorThreadPool - ================线程池华丽分割线================

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

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

相关文章

uniapp 微信小程序 上下滚动的公告通知(只取前3条)

效果图&#xff1a; <template><view class"notice" click"policyInformation"><view class"notice-icon"><image mode"aspectFit" class"img" src"/static/img/megaphone.png"></i…

行业追踪,2023-08-07

自动复盘 2023-08-07 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

0807|IO进程线程day9 IPC对象概念及示例(消息队列、共享内存、信号灯集)

0 什么是IPC机制 概念&#xff1a; IPC机制&#xff1a;Inter Process Communication&#xff0c;即进程间通信机制。 进程与进程间的用户空间相互独立&#xff0c;内核空间共享。所以如果要实现进程间的通信&#xff0c;需要使用进程间通信机制。 分类&#xff08;3类…

资深测试总结,Web自动化测试POM设计模式封装框架,看这篇就够了...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 线性脚本 import…

Maven分模块-继承-聚合-私服的高级用法

Maven分模块-继承-聚合-私服的高级用法 JavaWeb知识&#xff0c;介绍Maven的高级用法&#xff01;&#xff01;&#xff01; 文章目录 Maven分模块-继承-聚合-私服的高级用法1. 分模块设计与开发1.1 介绍1.2 实践1.2.1 分析1.2.2 实现 1.3 总结 2. 继承与聚合2.1 继承2.1.1 继承…

服了呀,现在的00后,实在是太卷了

现在的小年轻真的卷得过分了。前段时间我们公司来了个00年的&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天&#xff0c;原来这位小老弟家里条…

收藏这8个好用的原型设计工具,轻松制作原型图

在设计工作中&#xff0c;原型设计是非常关键的一步&#xff0c;而原型设计工具又能帮助设计师更轻松地完成设计工作。今天本文将与大家分享8个好用的原型设计工具&#xff0c;一起来看看吧&#xff01; 1、即时设计 即时设计是一个能在线协作的原型工具&#xff0c;也就是说…

DataGrip 配置 HiveServer2 远程连接访问

文章目录 集群配置 HiveServer2 服务DataGrip 配置 HiveServer2 访问 Hive 集群配置 HiveServer2 服务 1.在 Hive 的配置文件 hive-site.xml 中添加如下参数&#xff1a; <!-- 指定 HiveServer2 运行端口&#xff0c;默认为&#xff1a;10000 --><property><na…

ELK日志分析系统简介

ELK日志分析系统简介 ElasticsearchLogstashKibana主要功能Kibana日志处理步骤ELK的工作原理 日志服务器 提高安全性 集中存放日志 缺陷 ​ 对日志的分析困难 ELK日志分析系统 Elasticsearch 概述:提供了一个分布式多用户能力的全文搜索引擎 核心概念 接近实时 集群 节…

关于安卓jar包修改并且重新发布

背景&#xff1a; 对于某些jar包&#xff0c;其内部是存在bug的&#xff0c;解决的方法无外乎就有以下几种方法&#xff1a; &#xff08;1&#xff09;通过反射&#xff0c;修改其赋值逻辑 &#xff08;2&#xff09;通过继承&#xff0c;重写其方法 &#xff08;3&#xff0…

SQL-每日一题【1164. 指定日期的产品价格】

题目 产品数据表: Products 写一段 SQL来查找在 2019-08-16 时全部产品的价格&#xff0c;假设所有产品在修改前的价格都是 10 。 以 任意顺序 返回结果表。 查询结果格式如下例所示。 示例 1: 解题思路 1.题目要求我们查找在 2019-08-16 时全部产品的价格&#xff0c;假设所…

【Kubernetes】Kubernetes之Kubeadm部署

Kubeadm 一、Kubeadm 部署1. 环境准备2. 所有节点安装 docker3. 所有节点安装 kubeadm&#xff0c;kubelet 和 kubectl4. 部署 K8S 集群4.1 配置 master01 节点4.2 配置 node 节点 二、Kubeadm 高可用部署1. 环境准备2. 所有节点安装 docker2. 所有节点安装kubeadm&#xff0c;…

【大数据】Flink 详解(一):基础篇

Flink 详解&#xff08;一&#xff09;&#xff1a;基础篇 1、什么是 Flink &#xff1f; Flink 是一个以 流 为核心的高可用、高性能的分布式计算引擎。具备 流批一体&#xff0c;高吞吐、低延迟&#xff0c;容错能力&#xff0c;大规模复杂计算等特点&#xff0c;在数据流上提…

如何搭建一个成功的酒店小程序?

随着移动互联网的发展&#xff0c;小程序成为了不可忽视的商业工具之一。对于酒店行业来说&#xff0c;开发一个酒店预订小程序可以为客户提供更加便捷的预订方式&#xff0c;同时也带来了更多的商机。下面&#xff0c;我们将介绍一个简单的搭建流程&#xff0c;帮助新手快速上…

公会发展计划 (GAP) 第 4 季:塑造 YGG 的成就版图

基于前三个赛季所取得的成果&#xff0c;Yield Guild Games&#xff08;YGG&#xff09;自豪地宣布推出 公会发展计划&#xff08;GAP&#xff09;第 4 季。公会最近的一些精英成员将在本季加入公会&#xff0c;公会成员将在全新的任务中磨练自己的技能&#xff0c;建立自己在 …

HOT80-划分字母区间

leetcode原题链接&#xff1a;划分字母区间 题目描述 给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。注意&#xff0c;划分结果需要满足&#xff1a;将所有划分结果按顺序连接&#xff0c;得到的字符串仍然是 s 。返回…

ArcGIS Pro简介下载安装地址

ArcGIS Pro简介 ArcGIS Pro是一款功能强大的地理信息系统&#xff08;GIS&#xff09;软件&#xff0c;由Esri开发。它为用户提供了一种直观、灵活且高效的方式来处理、分析和可视化地理数据。ArcGIS Pro具有现代化的用户界面和工作流程&#xff0c;使用户能够更好地利用地理信…

修改k8s pod的挂载目录

1、找到挂载的服务 kubectl get service2、编辑pod的环境配置 kubectl edit deployment vendor-basic-bill-executor3、找到需要挂载的目录

Kubernetes(K8s)从入门到精通系列之十:使用 kubeadm 创建一个高可用 etcd 集群

Kubernetes K8s从入门到精通系列之十&#xff1a;使用 kubeadm 创建一个高可用 etcd 集群 一、etcd高可用拓扑选项1.堆叠&#xff08;Stacked&#xff09;etcd 拓扑2.外部 etcd 拓扑 二、准备工作三、建立集群1.将 kubelet 配置为 etcd 的服务管理器。2.为 kubeadm 创建配置文件…

【MATLAB第64期】【保姆级教程】基于MATLAB的SOBOL全局敏感性分析模型运用(含无目标函数,考虑代理模型)

【MATLAB第64期】【保姆级教程】基于MATLAB的SOBOL全局敏感性分析模型运用&#xff08;含无目标函数&#xff0c;考虑代理模型&#xff09; 版本更新&#xff1a; 2023/8/5&#xff1a; 1.因BP作为代理模型不稳定&#xff0c;经过测试&#xff0c;libsvm比rf /bp 效果稳定且精…