构造函数已赋值,为何HashMap在run()方法中为空?
DirWatcher的
files HashMap在Timer调度时为空的问题排查与解决 问题核心
开发配置处理器时,DirWatcher类的files HashMap在构造函数初始化后明明有值,但Timer调度执行run()方法时却为空,导致所有文件被误判为新增操作。
可能的原因及解决步骤
1. 子类隐藏了父类的files变量
如果你的匿名DirWatcher实例中重新定义了同名的files HashMap,会覆盖父类的变量——构造函数初始化的是父类的files,但run()方法访问的是子类的空变量。
解决:检查匿名子类代码,确保没有重复定义files变量。父类中定义protected Map<File, Long> files,子类直接使用即可,不要重新声明。
2. 线程可见性问题
Timer的run()方法在独立线程执行,普通HashMap不保证线程间的可见性,构造函数中写入的files数据可能无法被run()所在线程读取到。
解决:
- 用
volatile修饰files变量,保证变量的跨线程可见性; - 替换为线程安全的
ConcurrentHashMap,避免并发修改问题:protected volatile Map<File, Long> files = new ConcurrentHashMap<>();
3. 实例不一致
可能Timer调度的不是你初始化的那个DirWatcher实例,比如代码中不小心创建了多个实例。
验证:在构造函数和run()方法中打印实例的哈希值,确认是否为同一个对象:
// 构造函数中 System.out.println("DirWatcher实例哈希: " + this.hashCode()); // run()方法中 System.out.println("运行的实例哈希: " + this.hashCode());
如果两个哈希值不同,说明调度的是另一个实例,检查ConfigHandler中创建和调度任务的代码,确保只创建一个DirWatcher实例并交给Timer调度。
4. 初始化逻辑异常(排除项)
虽然你说构造后日志显示有值,但可以再确认初始化代码是否正确:
- 检查
getConfigFiles()方法是否正确过滤出JSON文件; - 确保遍历目录时没有抛出未捕获的异常,导致初始化中断。
修正后的示例代码
DirWatcher抽象类
public abstract class DirWatcher extends TimerTask { protected volatile Map<File, Long> files = new ConcurrentHashMap<>(); private final File configDir; public DirWatcher(String dirPath) { this.configDir = new File(dirPath); List<File> configFiles = getConfigFiles(); for (File f : configFiles) { files.put(f, f.lastModified()); System.out.println("初始化添加文件: " + f.getName() + ",实例哈希: " + this.hashCode()); } } protected List<File> getConfigFiles() { List<File> result = new ArrayList<>(); if (configDir.isDirectory()) { File[] files = configDir.listFiles((dir, name) -> name.endsWith(".json")); if (files != null) { result.addAll(Arrays.asList(files)); } } return result; } @Override public void run() { System.out.println("运行实例哈希: " + this.hashCode()); System.out.println("当前files大小: " + files.size()); List<File> currentFiles = getConfigFiles(); // 检查新增/修改 for (File f : currentFiles) { Long storedModified = files.get(f); if (storedModified == null) { handleAdd(f); files.put(f, f.lastModified()); } else if (f.lastModified() > storedModified) { handleModify(f); files.put(f, f.lastModified()); } } // 检查删除 Set<File> storedFiles = new HashSet<>(files.keySet()); storedFiles.removeAll(currentFiles); for (File f : storedFiles) { handleDelete(f); files.remove(f); } } protected abstract void handleAdd(File file); protected abstract void handleModify(File file); protected abstract void handleDelete(File file); }
ConfigHandler中的调度代码
public class ConfigHandler { public void startConfigWatcher() { Timer timer = new Timer(); DirWatcher watcher = new DirWatcher("/your/config/dir") { @Override protected void handleAdd(File file) { // 实现新增配置逻辑 } @Override protected void handleModify(File file) { // 实现更新配置逻辑 } @Override protected void handleDelete(File file) { // 实现删除配置逻辑 } }; // 每5秒执行一次 timer.scheduleAtFixedRate(watcher, 0, 5000); } }
内容的提问来源于stack exchange,提问作者samwit
相关产品推荐
相关产品推荐

