我想按顺序运行多个计时器。当一个计时器完成时,下一个计时器应该开始。我想使用Handler类,但这会产生并行运行计时器的效果。如下面的输出所示。
有没有一种方法可以让Timer操作阻塞线程,直到它完成,或者有没有更好的方法来实现这一点?也许用Futures或者Kotlin协程?
我是Android新手。在iOS上,我已经能够通过OperationQueue/Operation(设置isAsynchronous = true)来实现这一点。
class SequentialTimerTasks {
private val handlerThread: HandlerThread = HandlerThread("HandlerThread")
private lateinit var threadHandler: Handler
class TimerCountTask(private val id: Int) : TimerTask() {
private val TAG = "TimerCountTask"
var count = 0
override fun run() {
Log.d(TAG, "Runnable $id RUNNING TIMER $count")
count++
if (count >=10) {
Log.d(TAG, "Runnable $id CANCEL TIMER $count")
this.cancel()
}
}
}
class RunnableTask(private val id: Int) : Runnable {
private val TAG = "RunnableTask"
override fun run() {
Log.d(TAG, "Runnable $id run() called")
val timer = Timer()
timer.schedule(TimerCountTask(id), 0, 1000)
}
}
fun start() {
handlerThread.start()
threadHandler = Handler(handlerThread.looper)
threadHandler.post(RunnableTask(1))
threadHandler.post(RunnableTask(2))
}
}
输出
Runnable 1 run() called
Runnable 2 run() called
Runnable 1 RUNNING TIMER 0
Runnable 2 RUNNING TIMER 0
Runnable 2 RUNNING TIMER 1
Runnable 1 RUNNING TIMER 1
Runnable 2 RUNNING TIMER 2
Runnable 1 RUNNING TIMER 2
Runnable 2 RUNNING TIMER 3
Runnable 1 RUNNING TIMER 3
Runnable 2 RUNNING TIMER 4
Runnable 1 RUNNING TIMER 4
Runnable 2 RUNNING TIMER 5
Runnable 1 RUNNING TIMER 5
Runnable 2 RUNNING TIMER 6
Runnable 1 RUNNING TIMER 6
Runnable 2 RUNNING TIMER 7
Runnable 1 RUNNING TIMER 7
1条答案
按热度按时间iecba09b1#
你使用
HandlerThread
是多余的--这个类在你的代码中没有做任何有用的事情,它的Thread并不比你自己启动的任何随机线程或其他库创建的线程好多少。当然,它有一个Looper/Handler,但是你没有用Handler做任何有用的事情来证明它的存在。Timer
是Java 5之前的Java版本遗留下来的一个古老的东西。它的存在早于Android,现在没有人应该使用它。引用Timer的文档:Java5.0引入了java.util.concurrent包,其中的一个并发实用程序是ScheduledThreadPoolExecutor,它是一个线程池,用于以给定的速率或延迟重复执行任务。
代码中最大的错误是使用了两个单独的线程池:单线程
HandlerThread
“池”和Timer
内部使用的隐藏线程池。通常,您应始终最大限度地减少代码中多线程的使用,并将“正常”代码与多线程工件隔离。使用多种类型的线程(Android主线程除外)与此目的背道而驰。理论上,可以修复原始代码使其按预期工作,但由于上述原因,我建议放弃
HandlerThread
和Timer
,并切换到基于ScheduledThreadPoolExecutor的单线程池:与原始代码不同,上面的代码只在1个线程上运行业务逻辑-ScheduledThreadPoolExecutor线程。
这允许您利用 * 自然互斥 *:尽管没有执行显式线程同步,您的代码也不会与自身竞争或并发运行...因为只有一个线程。