You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java子类访问父类缓存Process时显示进程已退出问题排查

问题描述

定义抽象类A,类中维护一个protected修饰的Hashtable类型成员变量processCache,用于存储类A内部启动的进程对应的Process实例。类B继承自类A,在类B的重写方法中取出processCache中的Process实例时,判断得到进程已退出;但如果在类A内部访问同一个Process实例,进程处于存活状态且可正常获取执行结果。

初始问题代码如下:

public abstract class A {

    protected final Map<String, Process> processCache = new Hashtable<>();

    public void processResults(String processId) {
        getScanProcessResult(processId);
        // other logic
    }

    protected abstract String getScanProcessResult(String id);
}

public class B extends A {

    @Override
    protected String getScanProcessResult(String processId) {
        Process process = super.processCache.get(processId);
        if (process.isAlive) {
            // 实际判断为进程不存活
        }
    }
}

功能实现场景:
系统共配置2个批处理任务:

  • 第一个任务启动若干进程,并将对应的Process对象存入processCache
  • 第二个任务在首个任务启动1分钟后触发,从缓存的Process对象中读取进程执行结果

如果将判断逻辑直接写在类A的processResults方法中,功能可正常运行,对应代码如下:

public void processResults(String processId) {
    Process process = processCache.get(processId);
    if (process.isAlive) {
        // 实际判断为进程存活
    }
    // other logic
}
问题根因

按出现概率从高到低排序,核心原因有以下几类:

  • 成员变量遮蔽(Field Shadowing,最高概率)
    实际业务代码中,类B自行定义了和父类A同名的processCache成员变量,和父类的processCache是完全独立的两个实例:

    1. 父类A启动进程、存入缓存、以及在processResults方法中访问的,都是父类A中定义的processCache,里面存的是刚启动的存活Process实例
    2. 你在类B的重写方法中,遗漏了super.前缀,没有访问父类的缓存,而是直接访问了B类自己定义的processCache,这个缓存里存的是历史执行完成、已经退出的旧Process实例,因此判断为不存活。你给出的示例代码中写了super.processCache属于简化后的写法,和实际代码存在偏差。
  • 多实例缓存隔离(次高概率)
    你使用的批处理框架(Quartz、Spring Batch、XXL-JOB等)没有将类A/B配置为单例模式,每次触发任务时都会创建新的类实例:

    1. 第一个任务启动时创建的实例,往自己持有的processCache里存入了存活的Process实例
    2. 第二个任务触发时创建了全新的B实例,这个新实例的processCache中存储的是历史已退出的旧进程实例,因此判断为不存活
      你在A类的processResults方法中测试时,是在同一个实例的调用链内完成存、取、判断全流程,没有跨实例访问,因此可以正常拿到存活的进程实例。
  • 其他低概率原因

    1. 子类重写方法中,拿到Process实例后提前执行了关闭流、调用waitFor()、触发进程销毁的逻辑,导致进程提前退出
    2. 集群部署批处理任务时未配置任务路由,两个任务被调度到不同集群节点执行,跨节点无法访问其他节点JVM内存中存储的Process实例,拿到的是本节点存储的历史已退出进程
    3. 代码编写错误:将Process.isAlive()方法调用误写为字段访问process.isAlive,没有真正执行进程存活判断逻辑,拿到的是错误的默认值。

内容的提问来源于stack exchange,提问作者aminbhst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 22:27:35