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

如何判断Timer是否完成所有任务?多TimerTask场景实现方法咨询

如何判断Timer的所有任务是否执行完毕或处于空闲状态

确实,Java/Kotlin标准库的Timer类并没有提供直接的API来查询所有任务是否完成或者Timer是否处于空闲状态——它只允许你追踪单个TimerTask的状态(比如cancel()或者isScheduled()),但没法全局判断。不过我们可以通过包装Timer并跟踪任务生命周期来实现这个需求,下面是一个可行的方案:

核心思路

因为Timer是单线程执行所有任务的,所以我们可以:

  • 自定义一个TrackableTimer继承自Timer,内部维护一个线程安全的计数器,用来记录当前待执行或正在执行的任务数量
  • 重写所有schedule相关方法,将用户传入的TimerTask包装成一个代理任务,在任务执行前后更新计数器
  • 提供isIdle()方法来判断计数器是否为0(即没有待执行/正在执行的任务),甚至可以提供waitForIdle()方法让线程阻塞直到所有任务完成

完整代码实现

import java.util.*
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.ReentrantLock

class TrackableTimer(name: String? = null) : Timer(name) {
    // 跟踪待执行/正在执行的任务数,原子类保证线程安全
    private val taskCount = AtomicInteger(0)
    private val lock = ReentrantLock()
    private val idleCondition: Condition = lock.newCondition()
    private var isCanceled = false

    override fun schedule(task: TimerTask, delay: Long) {
        super.schedule(wrapTask(task), delay)
    }

    override fun schedule(task: TimerTask, delay: Long, period: Long) {
        super.schedule(wrapTask(task), delay, period)
    }

    override fun schedule(task: TimerTask, time: Date) {
        super.schedule(wrapTask(task), time)
    }

    override fun schedule(task: TimerTask, firstTime: Date, period: Long) {
        super.schedule(wrapTask(task), firstTime, period)
    }

    override fun scheduleAtFixedRate(task: TimerTask, delay: Long, period: Long) {
        super.scheduleAtFixedRate(wrapTask(task), delay, period)
    }

    override fun scheduleAtFixedRate(task: TimerTask, firstTime: Date, period: Long) {
        super.scheduleAtFixedRate(wrapTask(task), firstTime, period)
    }

    override fun cancel(): Boolean {
        lock.lock()
        try {
            isCanceled = true
            idleCondition.signalAll()
            return super.cancel()
        } finally {
            lock.unlock()
        }
    }

    /**
     * 判断Timer是否处于空闲状态(无待执行/正在执行的任务)
     */
    fun isIdle(): Boolean {
        return taskCount.get() == 0 || isCanceled
    }

    /**
     * 阻塞当前线程,直到Timer变为空闲状态
     */
    fun waitForIdle() {
        lock.lock()
        try {
            while (!isIdle()) {
                idleCondition.await()
            }
        } finally {
            lock.unlock()
        }
    }

    private fun wrapTask(originalTask: TimerTask): TimerTask {
        taskCount.incrementAndGet()
        return object : TimerTask() {
            override fun run() {
                try {
                    originalTask.run()
                } finally {
                    // 如果是一次性任务,执行完毕后减少计数;周期性任务会重复调度,不减少计数
                    if (!originalTask.isPeriodic) {
                        val count = taskCount.decrementAndGet()
                        lock.lock()
                        try {
                            if (count == 0) {
                                idleCondition.signalAll()
                            }
                        } finally {
                            lock.unlock()
                        }
                    }
                }
            }
        }
    }
}

使用示例

用你提供的代码改造一下,就能轻松跟踪Timer状态:

import timber.log.Timber

fun main() {
    val timer = TrackableTimer()
    timer.schedule(object : TimerTask() {
        override fun run() {
            Timber.d("task1")
        }
    }, 1000)
    timer.schedule(object : TimerTask() {
        override fun run() {
            Timber.d("task2")
        }
    }, 3000)

    // 示例1:定时检查是否空闲
    Timer().scheduleAtFixedRate(object : TimerTask() {
        override fun run() {
            Timber.d("Timer is idle? ${timer.isIdle()}")
        }
    }, 500, 500)

    // 示例2:阻塞等待所有任务完成
    Thread {
        timer.waitForIdle()
        Timber.d("All tasks are done! Timer is now idle.")
    }.start()
}

注意事项

  • 对于周期性任务(比如scheduleAtFixedRate或带period参数的schedule),因为任务会重复执行,所以isIdle()会一直返回false,直到你手动调用cancel()终止这些任务
  • TrackableTimer的cancel()方法会标记Timer为已取消,此时isIdle()会返回true,同时唤醒所有在waitForIdle()中阻塞的线程
  • 计数器用AtomicInteger保证线程安全,因为可能有多个线程同时调用schedule方法添加任务

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 16:32:58