大量mapper IO优化(使用多线程异步+CountDownLatch)

JUnit与Mockito核心面试指南:从基础到高级场景解析 单元测试是保障软件质量、实现持续集成的基石,而JUnit和Mockito作为Java生态中最主流的测试框架,其掌握程度直接反映了开发者的工程实践能力。JUnit提供了完整的测试生命周期管理、丰富的断言机制以及参数化测试等核心功能,而Mockito则通过模拟对象、行为验证等机制,实现了依赖隔离与协作测试。理解这两个框架的设计原理与最佳实践,不仅能编写出健壮、可维护的测试代码,更是应对技术面试、区分“会用”与“精通”的关键。在实际开发中,诸如@Mock与@Spy的应用场景、void方法的测试策略、以及异步代码的 阅读详情
实战业务优化方案总结—主目录https://blog.youkuaiyun.com/grd_java/article/details/124346685

经过测试,优化前的接口需要20多秒才能返回结果,优化后一般只需要5秒左右,如果查询频繁会变成500ms左右(因为有缓存)。

  1. 我的场景是,单个查询接口,涉及大量IO操作,无法减少IO的数量。
  2. 每个IO都是去数据库查询IO,不考虑优化sql,使用其它方法优化接口响应速度。

当查询大报表,并且sql没有太大优化空间的情况下,该如何提升效率呢?

  1. 也就是说现在IO太多,但是也没办法,业务确实需要这么多的IO
  2. 单个IO的效率优化,已经没有太多优化空间了,也就是优化sql的方案不可取
  3. 那么问题就是如何让这些IO能快一点

一般这种情况,就可以考虑多线程了,而且大的报表一般是不用考虑高并发的。所以直接将内容都写到方法中,不定义到类中,就没有线程安全问题。因为没有高并发,也不用考虑栈溢出的问题(每个线程执行都会有一个,线程私有,生命周期与线程相同,是Java方法执行的线程内存模型,每个方法被执行时,Java虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息)

当然,用到多线程,就需要考虑很多线程同步问题,而且异步执行IO,如何最终整合结果,都是需要解决的问题

我采用的方案如下

  1. 使用submit()方法进行异步提交
  2. 使用Callable接口的call方法,不使用Runnable接口的run。习惯了,需要返回值的场景,我都统一用Callable,用其它的也行。
  3. Callable接口的call方法可以给我们一个Future类型的返回值(不是只有它可以给Future返回值),我们可以通过这个Future获取线程中代码的返回值
  4. 使用JUC工具类中的倒数门栓CountDownLatch来做线程同步
  5. 为了不重复的写线程代码,编写统一工具类,通过反射来进行代码的执行

想要实现的效果如下(我希望和原来直接调用mapper接口一样简单,并且还能将单线程同步IO,实现为多线程异步IO。)

  1. 没改之前的代码,直接调用mapper接口,但是只有执行完第一个接口,才能执行第二个,以此类推。
List<String> provinces = cmsReportMapper.querySaleProvince();
List<ConfirmationsDTO> confirmationsDTOS = cmsReportMapper.queryConfirmationsByMonth(currentYear);
List<ConfirmationsDTO> confirmationsDTOSTotal = cmsReportMapper.queryConfirmationsTotal(currentYear);
  1. 改之后的,可以发现,对于调用mapper几乎是一样的,只不过需要额外传输反射需要的东西和CountDownLatch倒数门栓对象。不过实现了异步,这些mapper将一起异步执行。
Future<Object> provincesFuture = statementThreadUtils.runOneIOLatchCountDown(cmsReportMapper, latch, "querySaleProvince", null);
Future<Object> confirmationsDTOSFuture = statementThreadUtils.runOneIOLatchCountDown(cmsReportMapper, latch, "queryConfirmationsByMonth", oneStringClass, currentYear);
Future<Object> confirmationsDTOSTotalFuture =statementThreadUtils.runOneIOLatchCountDown(cmsReportMapper,latch,"queryConfirmationsTotal",oneStringClass,currentYear);
  1. 完整使用的形式,可见实现起来还是很方便的。让所有IO都异步执行了。
/**
     * 用给定的初始值,创建一个新的线程池 =======>>>>>>可使用全局配置的线程池,推荐定义处理IO密集型的专用线程池
     * @param corePoolSize 核心线程数量
     * @param maximumPoolSize 最大线程数量 (线程等待时间与线程CPU时间之比 + 1)* CPU数目
     * @param keepAliveTime 当线程数大于核心线程数量时,空闲的线程可生存的时间
     * @param unit 时间单位
     * @param workQueue 任务队列,只能包含由execute提交的Runnable任务
     * @param threadFactory 工厂,用于创建线程给线程池调度的工厂,可以自定义
     * @param handler 拒绝策略(可以自定义,JDK默认提供4种),当线程边界和队列容量已经满了,新来线程被阻塞时使用的处理程序
     */
    //《Java并发编程实战》 IO 密集型计算场景;;;;线程数 = CPU 核心数 * (1 + IO 耗时/ CPU 耗时)
    //此系统,IO耗时为400,CPU耗时为4 ===== 101 * 核心数 ===== 101*8
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,808,10,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(50),Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());
    /**20220421-yinzhipeng=====>>>>>>>>>优化响应速度 ===>> 优化前 800ms ====>>>> 优化后 200ms**/
        @Override
    public List<ConfirmationsDTO> queryConfirmationsBySaleProvince(String currentYear) {
        LinkedList<ConfirmationsDTO> result  = new LinkedList<>();

        try{
            //倒数门栓,用于同步线程
            final CountDownLatch latch = new CountDownLatch(3);
            //报表线程工具类
            StatementThreadUtils statementThreadUtils = new StatementThreadUtils(threadPoolExecutor);
            //用于反射,代表要调用的Mapper接口,参数列表为一个String
            Class[] oneStringClass = {String.class};

//            List<String> provinces = cmsReportMapper.querySaleProvince();
//            provinces.add("其他");
//            List<ConfirmationsDTO> confirmationsDTOS = cmsReportMapper.queryConfirmationsByMonth(currentYear);
//            List<ConfirmationsDTO> confirmationsDTOSTotal = cmsReportMapper.queryConfirmationsTotal(currentYear);
            Future<Object> provincesFuture = statementThreadUtils.runOneIOLatchCountDown(cmsReportMapper, latch, "querySaleProvince", null);
            Future<Object> confirmationsDTOSFuture = statementThreadUtils.runOneIOLatchCountDown(cmsReportMapper, latch, "queryConfirmationsByMonth", oneStringClass, currentYear);
            Future<Object> confirmationsDTOSTotalFuture =statementThreadUtils.runOneIOLatchCountDown(cmsReportMapper,latch,"queryConfirmationsTotal",oneStringClass,currentYear);
            //=================latch.await();=========================//
            latch.await();//等待所有异步都完成,倒数门栓的个数count=0,执行后面代码
            List<String> provinces = (List<String>)provincesFuture.get();
            provinces.add("其他");
            List<ConfirmationsDTO> confirmationsDTOS = (List<ConfirmationsDTO>)confirmationsDTOSFuture.get();
            List<ConfirmationsDTO> confirmationsDTOSTotal =(List<ConfirmationsDTO>)confirmationsDTOSTotalFuture.get();
            //==================latch.await();========================//
            //逻辑处理代码几百行,略。。。。。。。。。。。。。。。。。
            provinces.forEach(province -> {}
                
            result.addFirst(confirmation);
            return result;
        }catch (Exception e){
            e.printStackTrace();
            log.error("cms确认书件数统计表SystemError-->"+e.getMessage());
            return result;
        }


    }

具体工具类是如何封装的呢?就是简单的异步代码,用反射调用了mapper接口
在这里插入图片描述

当然,还提供了批量处理的工具方法,使用效果如下
在这里插入图片描述

String minSignatureDate = cmsReportMapper.queryMinSignatureDate();
String currentDate = DateUtils.currentDate();
if(StringUtils.isEmpty(endTime)){
    endTime = currentDate;
}
if(StringUtils.isEmpty(startTime)){
    startTime = minSignatureDate;
}

//倒数门栓,用于同步线程
final CountDownLatch latch = new CountDownLatch(9);
//报表线程工具类
StatementThreadUtils statementThreadUtils = new StatementThreadUtils(threadPoolExecutor);
//要调用的接口的参数表和参数,重复率很高,所以统一指定
Class[] threeString = {String.class, String.class, String.class};
Class[] twoString = {String.class, String.class};
Object[] threeArgs = {null, startTime, endTime};
Object[] twoArgs = {startTime, endTime};

//2021特殊企划件保费省份分布
List<PremiumProvinceDTO> areaSpecialPremium2021 = new ArrayList<>();
//2021延迟申请件保费省份分布
List<PremiumProvinceDTO> areaDelayPremium2021 = new ArrayList<>();

//2021特殊企划件趸交、3年期、五年期、10年期保费省份分布  目前只有三年期和十年期
List<ConfirmationPremiumDTO> specialPlanPremiumYearByTime = new ArrayList<>();
//2021延迟申请件趸交、3年期、五年期、10年期保费省份分布
List<ConfirmationPremiumDTO> delayPremiumYearByTime = new ArrayList<>();
//===============批量异步=====================下面是上面注释的异步submit代码的替换新式,所需代码量更少==============================================//
//要调用的mapper接口,和方法
Object[] mappers = {
        cmsReportMapper, cmsReportPremiumMapper, cmsReportPremiumMapper,
        cmsReportPremiumMapper, cmsReportPremiumMapper, cmsReportPremiumMapper,
        cmsReportPremiumMapper, cmsReportPremiumMapper, cmsReportPremiumMapper};
String[] mapperMethodNames = {
        "querySaleProvince", "queryAreaNormalPremiumTotal", "queryAreaSpecialPremium",
        "queryNormalPremiumYearByTime", "queryAreaSpecialPremium2021", "querySpecialPremiumYearByTime",
        "querySpecialPlanPremiumYearByTime", "queryAreaDelayPremium2021", "queryDelayPremiumYearByTime"};
//要调用的mapper对应方法的参数表
Class[][] methodArgsArr = {
        null, threeString, threeString,
        twoString, twoString, twoString,
        twoString, twoString, twoString};
//要调用mapper的方法实际要传的参数
Object[][] argsArr = {
        null, threeArgs, threeArgs,
        twoArgs, twoArgs, twoArgs,
        twoArgs, twoArgs, twoArgs};
//每个接口异步执行完成后,对应返回结果Future的key===可以不指定,默认用接口方法名作为key
String[] keys = {
        "provincesFuture", "areaNormalPremiumTotalFuture", "areaSpecialPremiumFuture",
        "normalPremiumYearByTimeFuture", "areaSpecialPremium2021Future", "specialPremiumYearByTimeFuture",
        "specialPlanPremiumYearByTimeFuture", "areaDelayPremium2021Future", "delayPremiumYearByTimeFuture"};
//进行批量异步
HashMap<String, Future> stringFutureHashMap =
        statementThreadUtils.runOneIOLatchCountDownMap(keys, mappers, latch, mapperMethodNames, methodArgsArr, argsArr);
//===============latch.await();=================//
latch.await();
List<String> provinces = (List<String>)stringFutureHashMap.get("provincesFuture").get();
provinces.add("其他");
//正常件保费省份分布
List<PremiumProvinceDTO> areaNormalPremiumTotal = (List<PremiumProvinceDTO>)stringFutureHashMap.get("areaNormalPremiumTotalFuture").get();
//特殊件(刨除2021年)保费省份分布
List<PremiumProvinceDTO> areaSpecialPremium = (List<PremiumProvinceDTO>)stringFutureHashMap.get("areaSpecialPremiumFuture").get();
//正常件保费 趸交、3年期、五年期、10年期
List<ConfirmationPremiumDTO> normalPremiumYearByTime = (List<ConfirmationPremiumDTO>)stringFutureHashMap.get("normalPremiumYearByTimeFuture").get();
//特殊件保费(刨除2021年) 趸交、3年期、五年期、10年期querySpecialPremiumYearByTime
List<ConfirmationPremiumDTO> specialPremiumYearByTime = (List<ConfirmationPremiumDTO>)stringFutureHashMap.get("specialPremiumYearByTimeFuture").get();
//如果endTime and startTime 均大于2021-12-31
areaSpecialPremium2021.addAll((List<PremiumProvinceDTO>)stringFutureHashMap.get("areaSpecialPremium2021Future").get());
areaDelayPremium2021.addAll((List<PremiumProvinceDTO>)stringFutureHashMap.get("areaDelayPremium2021Future").get());
specialPlanPremiumYearByTime.addAll((List<ConfirmationPremiumDTO> )stringFutureHashMap.get("specialPlanPremiumYearByTimeFuture").get());
delayPremiumYearByTime.addAll((List<ConfirmationPremiumDTO>)stringFutureHashMap.get("delayPremiumYearByTimeFuture").get());
//================latch.await();================//

工具类的源码如下

import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.*;
/**
 * 20220421==>>>yinzhipeng
 * 报表专用线程工具类
 * 主要用于优化 IO 密集型计算场景
 */
public class StatementThreadUtils {
    ThreadPoolExecutor threadPoolExecutor = null;
    public StatementThreadUtils(ThreadPoolExecutor threadPoolExecutor) {
        this.threadPoolExecutor = threadPoolExecutor;
    }

    /**
     * 一个用倒数门栓的IO执行(一个异步线程中,只负责一个IO,需要花费一个门栓)
     * @param o 要执行IO的对象
     * @param latch 倒数门栓
     * @param method 要执行的io方法
     * @param methodArgs 要执行的io方法的参数,没有就是null
     * @param args 方法的参数
     */
    public Future<Object> runOneIOLatchCountDown(Object o,CountDownLatch latch, String method,Class[] methodArgs,Object... args){
        Future<Object> submit = threadPoolExecutor.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                Object result = null;
                try{
                    Method method1 = o.getClass().getMethod(method,methodArgs);
                    result = method1.invoke(o, args);
//                    return result;
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    latch.countDown();
                    return result;
                }
            }
        });
        return submit;
    }
    /**
     * 多个用倒数门栓的IO执行(就是一个异步中,执行多个IO操作,多个IO只用一个门栓count-1和一个线程)
     * @param objs 要执行IO的对象
     * @param latch 倒数门栓
     * @param methods 要执行的io方法
     * @param methodArgsArr 要执行的io方法的参数,没有就是null
     * @param argsArr 方法的参数
     * @return
     */
    public Future<Object> runManyIOLatchCountDown(Object[] objs,CountDownLatch latch, String[] methods,Class[][] methodArgsArr,Object[][] argsArr){
        Future<Object> submit = threadPoolExecutor.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                ArrayList<Object> results = new ArrayList<>();
                try{
                    for (int i = 0; i < objs.length; i++) {
                        Object result = null;
                        Method method1 = objs[i].getClass().getMethod(methods[i],methodArgsArr[i]);
                        result = method1.invoke(objs[i], argsArr[i]);
                        results.add(result);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    latch.countDown();
                    return results;
                }
            }
        });
        return submit;
    }
    /**
     * 一个用倒数门栓的IO执行-----批量---返回List(同样是一个线程异步一个IO,只不过这个是批量的,可以用数组把需要异步的IO都传输过来)
     * @param objs 要执行IO的对象
     * @param latch 倒数门栓
     * @param methods 要执行的io方法
     * @param methodArgsArr 要执行的io方法的参数,没有就是null
     * @param argsArr 方法的参数
     * @return ArrayList<Future>
     */
    public ArrayList<Future> runOneIOLatchCountDownList(Object[] objs,CountDownLatch latch, String[] methods,Class[][] methodArgsArr,Object[][] argsArr){
        ArrayList<Future> futures = new ArrayList<>();
        for (int i = 0; i < objs.length; i++) {
            int finalI = i;
            Future<Object> submit = threadPoolExecutor.submit(new Callable<Object>() {
                @Override
                public Object call() throws Exception {
                    Object result = null;
                    try{
                        Method method1 = objs[finalI].getClass().getMethod(methods[finalI],methodArgsArr[finalI]);
                        result = method1.invoke(objs[finalI], argsArr[finalI]);
//                    return result;
                    }catch (Exception e){
                        e.printStackTrace();
                    }finally {
                        latch.countDown();
                        return result;
                    }
                }
            });
            futures.add(submit);
        }
        return futures;
    }
    /**
     * 一个用倒数门栓的IO执行-----批量---返回Map
     * @param objs 要执行IO的对象
     * @param latch 倒数门栓
     * @param methods 要执行的io方法
     * @param methodArgsArr 要执行的io方法的参数,没有就是null
     * @param argsArr 方法的参数
     * @return HashMap<String, Future>
     */
    public HashMap<String, Future> runOneIOLatchCountDownMap(Object[] objs,CountDownLatch latch, String[] methods,Class[][] methodArgsArr,Object[][] argsArr){
        return runOneIOLatchCountDownMap(methods,objs,latch,methods,methodArgsArr,argsArr);
    }
    /**
     * 一个用倒数门栓的IO执行-----批量---返回Map----指定key版
     * @param keys 异步执行后,保存到Map中的key。
     * @param objs 要执行IO的对象
     * @param latch 倒数门栓
     * @param methods 要执行的io方法
     * @param methodArgsArr 要执行的io方法的参数,没有就是null
     * @param argsArr 方法的参数
     * @return HashMap<String, Future>
     */
    public HashMap<String, Future> runOneIOLatchCountDownMap(String[] keys,Object[] objs,CountDownLatch latch, String[] methods,Class[][] methodArgsArr,Object[][] argsArr){
        HashMap<String, Future> futuresMap = new HashMap<>();
        for (int i = 0; i < objs.length; i++) {
            int finalI = i;
            Future<Object> submit = threadPoolExecutor.submit(new Callable<Object>() {
                @Override
                public Object call() throws Exception {
                    Object result = null;
                    try{
                        Method method1 = objs[finalI].getClass().getMethod(methods[finalI],methodArgsArr[finalI]);
                        result = method1.invoke(objs[finalI], argsArr[finalI]);
//                    return result;
                    }catch (Exception e){
                        e.printStackTrace();
                    }finally {
                        latch.countDown();
                        return result;
                    }
                }
            });
            futuresMap.put(keys[finalI],submit);
        }
        return futuresMap;
    }

    /**
     * 获得真正的处理对象,可能多层代理.
     */
    public static <T> T realTarget(Object target) {
        if (Proxy.isProxyClass(target.getClass())) {
            MetaObject metaObject = SystemMetaObject.forObject(target);
            return realTarget(metaObject.getValue("h"));
        }
        return (T) target;
    }
}
分布式锁实战:Redis与ZooKeeper方案对比与Redisson最佳实践 在分布式系统架构中,并发控制是确保数据一致性的核心技术挑战。其核心原理是通过协调多个服务节点对共享资源的访问顺序,防止数据竞争和状态不一致。这一技术为高并发场景下的资源安全访问提供了基础保障,广泛应用于微服务、云原生等现代架构。从技术价值看,它解决了分布式环境下传统单机锁失效的问题,是实现秒杀防超卖、分布式任务调度、配置更新等关键业务场景的基石。具体到实现层面,主流方案包括基于Redis的高性能实现和基于ZooKeeper的强一致性实现。Redis方案凭借其出色的性能成为高并发场景下的首选,而ZooKeep 阅读详情

相关推荐

2026 Java后端面试突击:核心考点与答题框架

在Java后端开发中,JVM内存管理与垃圾回收是性能调优的基础,理解参数如-XX:CompileThreshold及OOM排查能显著提升问题定位能力。同时,随着AI技术落地,Spring AI结构化输出成为新热点,它让模型返回值直接映射为Java实体类,打通业务集成链路。掌握MySQL事务、索引优化及并发编程等核心原理,是应对高并发场景的必备技能。本文从这些基础概念出发,结合实际面试场景,系统性梳理了JVM、并发、MySQL、Spring及AI大模型等高频考点,提供了一套可执行的短期突击答题框架与复习路径,

weixin_34332905的博客 485

Java 使用CountDownLatch实现网络同步请求,异步同时获取商品信息组装

CountDownLatch 是一个同步工具类,用来协调多个线程之间的同步,它能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。

xzh_blog 548

Java后端开发学习路线:从Spring到AI赋能的实战指南

Java作为企业级应用开发的主流语言,其技术生态围绕JVM虚拟机、并发编程和集合框架等核心机制构建。理解这些底层原理是掌握Spring框架等高级技术的基础,后者通过控制反转和面向切面编程等设计模式实现了高效的组件管理。在微服务架构和分布式系统成为主流的今天,掌握缓存、消息队列和性能监控等技术对构建高可用应用至关重要。随着AI工具的普及,开发者现在可以利用智能辅助进行代码生成、问题排查和系统设计,显著提升开发效率。本文聚焦于Java后端技术栈的系统学习路径,并结合AI应用实践,为开发者提供从基础到高阶的完整成

weixin_34062469的博客 322

34 mybatis-spring Mapper太多导致 StackOverflow

前言 前几天 项目上有这样的一个问题, 内存给的2G, 项目似乎是启动不起来, 然后 之后调整为 4G 项目就启动起来了 然后 这个问题, 我们最开始都没有太在意, 认为可能 初始化项目需要的内存稍微需要大一些吧 ? 然后 上周五, 和测试同事发布项目的时候, 又出现了这个问题, 然后 在测试环境 周四是能够启动起来, 然后 期间有一些小调整, 然后 周五发布项目 就发布不起了 ...

970655147的专栏 3045

【通俗易懂】Windows系统安装TensorRT

NVIDIA TensorRT是一个由NVIDIA公司开发的用于深度学习推理的高性能SDK。它专门设计用于在NVIDIA GPU上进行高效的神经网络推理,能够大幅度提升深度学习模型的推理速度和效率。TensorRT的主要特点包括:模型优化:TensorRT通过层融合、精度校准、动态形状等技术优化模型,减少推理时的计算量和内存占用。多精度推理:支持多种精度推理,包括FP32、FP16、INT8等,以平衡性能和精度。

王尼莫的博客 1587

Qt (高仿Visio)流程图组件开发(一) 效果展示及基本开发框架构思

最近因为工作原因需要使用Qt开发一个类似于Visio的流程图组件,需满足基本的流程图功能,图元类型可自定义扩展,不同图元存有各类自定义数据,可以保存为xml文件,可以读取xml文件生成流程图等等。

qq_43793182的博客 1万+

巧用CountDownLatch实现多线程并行工作

由于手机文件夹目录众多,单线程遍历全部文件夹找出所有的安装包会比较费时,但是假如开启多个线程并行去搜索不同的文件夹,然后再将结果汇总起来返回,那么效率就会明显有所提高。然而开启多个线程去搜索是很容易实现,但是由于每个线程耗时不同,有些线程搜索完毕了,但是有些线程可能还在搜索,怎么确保所有的线程都搜索完毕再把结果汇总起来返回呢?这时候借助这个类就能轻易地实现

逍遥阁 1406

机械式激光雷达实现原理以及特性总结

本文介绍了机械式激光雷达的技术原理和核心特性。该技术通过机械旋转结构实现360°三维扫描,采用飞行时间法测距并生成点云数据。核心优势包括全向扫描、长距高精度和成熟度高,但存在体积大、成本高、可靠性受限等局限。典型应用于自动驾驶测试车、测绘建模等领域。与固态激光雷达相比,机械式在视场角和探测距离方面有优势,但在体积、成本和可靠性方面处于劣势。该技术目前主要应用于对成本不敏感的专业场景。

start_up_go的博客 262

开启多个线程查询大量数据

转自:https://blog.youkuaiyun.com/qq_26607531/article/details/112343509 作者:壮壮是个智障啊 最近有个业务需求要批量导出大量的数据,但数据库在面对过多数据查询时效率就会很慢,于是考虑使用多个线程来实现。 这里使用了Callable的方式创建多线程,好处是有返回值 package com.next.jiangzh.film.dao; import java.util.List; import java.util.concurrent.Callable;

weixin_45650737的博客 828

PGM-Explainer实验总结

PGM-Explainer建立了一个概率图模型,为GNN提供实例级解释。 论文标题:PGM-Explainer: Probabilistic Graphical Model Explanations for Graph Neural Networks 论文地址:2010.05788.pdf (arxiv.org) PGM-Explainer实验 实验目的 研究PGM-Explainer的有效性 实验方案 合成数据集的节点分类 与其他解释器做对比实验 使用六个合成数据集。 每个输入图都是一个

笔记|思路|总结 1万+

【unity实战】Cinemachine虚拟相机实战,使用InputSystem+Cinemachine+CharacterController复刻各种主流游戏的相机控制

这里主要是探讨如何使用InputSystem+Cinemachine+CharacterController复刻各种主流游戏的相机控制,我们主要专注Cinemachine实战效果,所以并不会深入讨论Cinemachine和CharacterController比较细节的参数介绍。注意:前面为了测试方便,我还是先用的旧的输入系统代替InputSystem【推荐100个unity插件之10】Unity最全的最详细的Cinemachine(虚拟相机系统)介绍,详细案例讲解,快速上手。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 3750

mybatis的各种查询情况3 - 查询信息总量 count(*)以及返回总量

前面介绍了mybatis的各种查询情况的两种,接下去我们来看看其他的查询吧~~~~~ 本节中返回对象有新知识点,让我们一起提高吧。gogogo!!! 目录 1.接口部分 2.mapper映射文件部分 2.1大纲碎碎念 2.2 resultType返回类型 3.测试类 4.结果 4.1测试类结果 4.2数据库验证 5.结论 1.接口部分 接口部分用Integer或者int类型都是可以的,返回一个整数。 /** * 查询用户信息总记录数 */

m0_53753920的博客 1万+

k8s 不同node之间pod ip不通

底层k8s使用calico网络,ipip网络模式,kubevirt启动了2台虚拟机;在这两台虚拟机上再搭建k8s,calico网络,ipip网络模式。说明:我是使用helm安装的calico,改这个模式要改crd资源ippools。其他方式安装的calico修改方法可能不一样。在虚拟机上的k8s上启动了2个pod,分布在不同的node上,这两个pod不能ping通对方的pod ip。修改虚拟机之上的k8s集群的calico网络的ipipMode为Never即可,之前使用的是Always。

weixin_40548182的博客 4056

147.【2024Java八股-全网最全-10w字】

eg: 学校、院校、经验、年龄、跳槽频率…基本包括16种常见使用场景: 、数据共享分布式、、全局 ID、计数器、限流、位统计、购物车、用户消息时间线 timeline、、抽奖、点赞、签到、打卡、商品标签、商品筛选、用户关注、推荐模型、排行榜.详细讲解16种使用场景: https://blog.youkuaiyun.com/zxl646801924/article/details/123202381用户使用id进行查询文章的时候,首先会查询redis数据库,如果在redis中命中数据,那么redis就向用户返回查询的结果

qq_69683957的博客 1736

【100%通过率】2023华为od机试C卷【电脑病毒感染】C++ 实现

一个局域网内有很多台电脑,分别标注为 0 ~ N-1 的数字。相连接的电脑距离不一样,所以感染时间不一样,感染时间用t 表示。其中网络内一台电脑被病毒感染,求其感染网络内所有的电脑最少需要多长时间。如果最后有电脑不会感染,则返回-1.

MISAYAONE的博客 1727

把财务与管理会计装进一张表:读懂 S/4HANA 的 ACDOCA

别慌,这反而是设计所需。只是大量历史上为汇总、加速而建的索引与汇总表被淘汰或改造,很多被兼容视图 compatibility views 替代,通过视图去 ACDOCA 或 ACDOCT 取数,从而保证老代码还能 SELECT 到数据,但失去写权限。它把原来分散在多张表里的信息整合到一起,例如总账、固定资产、物料账、盈利能力分析 CO-PA、成本控制等维度,发布过的资料多次强调这一点。其二,查询必须带上高选择性的条件,尤其是 RLDNR、RBUKRS、GJAHR 这三个维度,能大幅降低列存扫描的代价。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 947

Java面试题汇总

用户再访问别的应用的时候,就会将这个ticket带上,作为自己认证的凭据,应用系统接受到请求之后会把ticket送到认证系统进行效验,检查ticket的合法性。在运行过程中,Jasper可以检测JSP文件的变化,并重新编译它们。在flush的过程中,缓存会被清空,内容被写入一个新的段中,并刷新到磁盘,旧的translog会被删除并创建一个新的translog。将JSP或Servlet放在相应的子目录中,然后压缩目录,生成一个.war文件,把这个文件放置到Tomcat的webapps目录下。

look4liming的专栏 58

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Spring Boot从入门到实战:构建预约服务系统全指南

Java后端开发中,框架选型往往决定学习与交付效率。Spring Boot 作为 Spring 生态的快速开发框架,以“约定大于配置”为核心,利用自动配置机制在启动时根据依赖装配组件,大幅降低环境搭建与集成成本。开发者只需关注业务代码,即可快速构建独立运行的 Web 应用。该技术栈尤其适合从零搭建 RESTful API、数据处理及实时通信场景。例如,设计一个包含用户、厨师与订单的预约服务系统时,可借助 Spring Boot 完成分层架构、事务控制、异步通知以及 WebSocket 实时推送等能力,整个过

weixin_34161083的博客 148

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

黑马点评项目 | Redis学习笔记「纯享版」10w字超详细总结(含资料)

这次笔记是本人二刷Redis实战篇黑马点评的8w字汇总笔记。如果需要资料,于本文末尾查找即可

2025优快云博客之星Top246,后端开发技术领域新星创作者。 3万+

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

2026最新Java八股文(完整版)

单个redis节点的并发能力是有限的,所以为了提高并发能力,我们需要搭建redis集群,就比如:主从复制。主从复制的流程主从复制主要分为:全量同步和增量同步。全量同步:在salve请求数据同步的时候会携带application Id和offset,如果master判断出applid和自己的不一样,就认为slave是第一次进行同步,所以会进行全量同步。

Ostkakah的博客 4万+

Java面试常见八股文

覆盖索引:查询时使用了索引,并且需要返回的列,在该索引中全部能够找到回表:通过非聚簇索引,找到对应的主键id值,再到聚簇索引中,根据主键id查询到叶子结点中存储的整行数据两个或两个以上的线程在执行过程中,因争夺共享资源而造成的一种互相等待的现象死锁的四个条件互斥:共享资源X和Y只能被一个线程占用请求与保持:线程T1已经取得共享资源X,在等待共享资源Y时,不会释放共享资源X不可抢占:其他线程不能强行抢占线程T1占有的资源循环等待:线程T1等待线程T2占有的资源,线程T2等待线程T1占有的资源。

m0_59372522的博客 634

Java工程师进阶指南:从基础到架构的实战修炼

Java作为企业级应用开发的核心语言,其技术生态涵盖了从基础语法到分布式架构的完整体系。理解Java虚拟机(JVM)的内存管理、垃圾回收机制以及并发编程模型,是构建高性能、高可用系统的理论基础。在实际工程实践中,这些原理转化为解决内存溢出、线程安全、性能调优等核心问题的能力。例如,通过分析GC日志定位内存泄漏,或利用JUC工具包设计高并发场景下的数据访问策略,能够显著提升系统稳定性与吞吐量。随着微服务与云原生架构的普及,Java工程师还需掌握分布式通信、异步处理等进阶技能,以应对复杂业务场景的挑战。本文聚焦

weixin_30333885的博客 467

Java基础学习路线与核心知识点详解:从语法到面试必备

在编程技术栈中,Java以跨平台、面向对象和生态成熟著称,是后端开发与大型系统构建的基石。掌握Java基础不仅是语法层面的熟练,更要理解集合框架、并发编程等底层机制,例如HashMap的哈希冲突处理与扩容原理,以及线程安全与锁的升级过程。从数据类型、面向对象设计到异常处理、IO与反射,每个环节都影响着代码质量与系统性能。在工程实践中,扎实的基础能帮助开发者快速定位并发异常、避免集合操作陷阱,并为学习Spring等框架铺平道路。无论是零基础入门还是准备技术面试,系统梳理Java核心知识体系都至关重要。本文以多

weixin_34380948的博客 435

java八股

····先解释一下aop、然后切面--抽出来的通用功能(日志、事务、权限)、通知、切入点(用在什么地方)、主要解决的问题是对不支持多继承的弥补(强共性继承、弱共性AOP)、然后说AOP是由动态代理来实现的(jdk-有接口、cglib);······当执行到monitorenter指令的时候会获取monitor(监视器锁)里面有俩个重要的参数_owner和_count当同一个线程获取锁的时候,count就会++来实现可重入锁;······轻量、IOC、AOP、MVC框架、事务管理、扩展性;

qq_52297130的博客 362

从Java基础到微服务场景:大厂面试考点与架构设计核心路径

Java开发者的成长往往始于基础概念,比如HashMap的哈希冲突与扩容机制、线程池中如何优雅等待所有任务完成。这些看似零散的知识点,其实是理解动态代理、Spring AOP等框架原理的基石。当业务演进到微服务阶段,服务拆分、注册中心(如Nacos)、接口文档聚合(如Knife4j整合)以及分布式事务成为新的核心挑战。掌握从底层JVM到上层微服务治理的完整链路,才能应对大厂面试中对技术选型、方案权衡和场景落地能力的追问。本文按基础→框架→微服务架构的路径,系统梳理了各个阶段的高频考点与追问逻辑,帮助开发者建

weixin_34025051的博客 468

java八股文极速版

时间和空间的权衡 值越高空间开销小但是增加了查找开销服务于从Key映射到index的Hash算法,在性能和内存的使用上取平衡,实现一个尽量均匀分布的Hash函数,选取16,是通过位运算的方法进行求取的。线程安全:当多线程执行同一段程序的时候,如果发生了和预期结果不一致的情况,就是线程不安全的,如果和预期结果一致就是线程安全的,可以加锁解决(把并行运行的线程变成串行化执行)。1.加锁 利用Synchronized或者ReenTrantLock来对不安全对象进行加锁。

PassionAnytime的博客 382
上一篇: 高性能分布式缓存Redis--- Redis底层结构和缓存原理 --- 持续更新
下一篇: 自定义Mybatis自动填充插件----mybatis-plus 自动填充失效、分页插件不向下传递拦截链
ydenergy_殷志鹏
博客等级 码龄7年 5885粉丝 543原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ydenergy_殷志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值