如何判断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
相关产品推荐
相关产品推荐

