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

Java线程延迟执行代码时调用timerStart无效问题求助

问题原因与解决方案

问题原因

  1. 线程可见性缺失:lastEdit变量没有标记为volatile,执行run()方法的线程会将变量缓存到自身工作内存中,其他线程修改lastEdit后,该线程无法及时感知主存中的最新值,导致判断逻辑一直使用旧的缓存值,看起来修改未生效。
  2. static方法调用误区:timerStart是static方法,你通过anotherThread.timerStart(12000)调用时,本质是调用类的static方法,和anotherThread实例无关。如果lastEdit是static变量,这部分本身无问题,但核心矛盾还是线程可见性。
  3. 忙循环的JIT优化问题:while(true)的空循环会触发JIT编译器优化,可能将lastEdit的读取操作直接优化为从寄存器读取,彻底忽略主存中的更新。

解决方案

方案1:修复线程可见性(最直接)

给lastEdit添加volatile修饰符,强制线程每次读取都从主存获取最新值,写入时立即同步到主存:

private static volatile long lastEdit; // 增加volatile修饰

public void run() {
    System.out.println("it is running");
    while (true) {
        if (System.currentTimeMillis() > lastEdit) {
            System.out.println("DELETE");
            timerStart(12000);
        }
        // 加入微小sleep,减少CPU空转
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            break;
        }
    }
}

public static void timerStart(int time) {
    lastEdit = System.currentTimeMillis() + time;
}

如果存在多线程同时调用timerStart的场景,lastEdit = ...不是原子操作(读取、计算、写入三步),此时需要用AtomicLong保证原子性:

private static final AtomicLong lastEdit = new AtomicLong();

public static void timerStart(int time) {
    lastEdit.set(System.currentTimeMillis() + time);
}

// run方法中的判断需修改为:
if (System.currentTimeMillis() > lastEdit.get())

方案2:使用更高效的定时方式(推荐)

放弃忙循环,用Java自带的ScheduledExecutorService实现延迟执行,既避免CPU空转,也天然解决线程同步问题:

private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private Future<?> currentTask;

public void start() {
    System.out.println("it is running");
    scheduleDelete(12000);
}

private void scheduleDelete(long delay) {
    // 取消之前的未完成任务
    if (currentTask != null && !currentTask.isDone()) {
        currentTask.cancel(false);
    }
    currentTask = scheduler.schedule(() -> {
        System.out.println("DELETE");
        scheduleDelete(12000); // 执行完成后调度下一次
    }, delay, TimeUnit.MILLISECONDS);
}

// 外部调用此方法重置延迟
public void resetTimer(int time) {
    scheduleDelete(time);
}

// 程序结束时关闭线程池
public void shutdown() {
    scheduler.shutdown();
}

这种方式无需手动处理变量同步,由线程池负责调度,可靠性和效率更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 12:30:55