我是一个可运行的实例,它在run
方法的末尾再次自我调度:
private class MyRunnable implements Runnable {
private volatile boolean cancelled = false;
private Handler handler;
public MyRunnable(Handler h){
handler = h;
}
@Override
public void run(){
//Do stuff
if(!cancelled){
//Preemtion possible here?
handler.postDelayed(this, 1000);
}
}
public void selfStart(){
cancelled = false;
handler.removeCallbacks(this);
handler.post(this);
}
public void selfCancel(){
cancelled = true;
handler.removeCallbacks(this);
}
}
runnable首先在主线程中安排从活动的selfStart
调用onStart
。
同时,可以从活动的selfCancel
以及广播接收器中外部取消(可以onStop
})。
AFAIK Runnable.run
,Activity.onStop
和BroadcastReceiver.onReceive
在同一个主题(主要主题)中运行,所以乍一看我认为不存在线程安全问题。
但看起来有时候,runnable正在其run
调用的中间被删除,然后它从活动或接收器中被取消,然后它重新开始并重新安排自己。
这可能吗?
更新:
我会尝试更好地解释这个问题。上面显示的类旨在定期在主线程中运行任务。在"做东西"在那里发表评论的实际代码是使用传递给TextView
构造函数的值更新MyRunnable
。活动取消当前的runnable,并在收到某些意图时启动新的runnable。尽管当前runnable总是被请求在创建新的runnable之前取消它,但有时它会与新的一起运行,因此文本视图显示交替的值。这不是预期的行为。
我认为如果runnable当前在主线程中运行,它将一直运行直到完成,然后其他runnables或事件处理程序将从队列中取出并在需要时执行,但是没有挂起事件或runnable可能是& #34;一半执行"。
主线程中运行的任务有两种与问题相关的任务:
MyRunnable
自我调度任务。运行然后再以1s的延迟自我发布。MyRunnable
实例并创建新R1'的事件处理程序。这些都是随机发生的,只执行一次。我考虑过两种情况。第一个:
第二个:
理论上,如果没有预设,并且只有一个线程,那么主线程中有时会有两个R1?
答案 0 :(得分:1)
由于你在selfStart或selfCancel上没有同步,这是完全可能的。
在run方法中的if语句检查selfCancel
的值后,可以在单独的线程上调用未发布的注释cancelled
。然后MyRunnable
会再次调用一次,这会在它被取消时立即结束。
答案 1 :(得分:1)
我的建议是将//Do stuff
移到已取消的支票内。
这可以避免竞争,无论有关哪些线程正在运行的假设。
@Override
public void run(){
if(!cancelled){
//Do stuff
handler.post(this);
}
}
一般来说,为了可维护性,尝试编写无论正在运行的线程如何都能正常工作的代码。你永远不知道什么时候有人会在其他线程上调用selfCancel()后来认为它没关系,当你假设他们不会这样做时。
答案 2 :(得分:0)
正如其他人所说,没有办法可以在单个线程中抢占runnable。我也认为这个想法很荒谬。对于我提出这些废话感到羞耻。
runnables本身没有任何问题。它们在活动的onStart
中启动,并从活动收到的意图或活动的onStop
中取消。这是问题的根源:假设onStart
和onStop
将以可预测的顺序运行。有时回到活动时,在第一个活动的onStart
之前执行了第二个onStop
。两个任务正在运行,事情搞砸到第一个任务永远不会终止的地步。
确保在没有先前终止任务的情况下没有启动任务解决了问题。