我有一个可运行的实例,它在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);
}
}
可运行对象首先在主线程中调度,该主线程从活动的
selfStart
调用onStart
。同时,可以从活动的
selfCancel
和广播接收器从外部取消可运行对象(调用onStop
)。AFAIK
Runnable.run
,Activity.onStop
和BroadcastReceiver.onReceive
在同一线程(主要线程)中运行,因此乍一看,我认为不会有线程安全问题。但是似乎有时,可运行对象在其
run
调用中间被预定义,然后从活动或接收方中取消,然后恢复并重新安排自身。这可能吗?
更新:
我会尽力解释这个问题。上面显示的类旨在在主线程中定期运行任务。在“做东西”注释中,实际上有代码使用传递给
TextView
构造函数的值来更新MyRunnable
。该活动将取消当前可运行的对象,并在收到某些意图时开始一个新的对象。尽管始终会要求当前可运行对象在创建新可运行对象之前取消自身,但有时它会与新可运行对象一起运行,因此文本视图显示的是交替值。这不是预期的行为。我以为如果该可运行对象当前正在主线程中运行,它将一直运行到完成,然后其他可运行对象或事件处理程序将从队列中取出并在需要时执行,但是没有待处理的事件或可运行对象可以被“半执行” 。
与该问题相关的在主线程中运行的任务有两种:
R1:
MyRunnable
自调度任务。运行,然后以1s的延迟再次自我发布。R2:请求取消当前
MyRunnable
实例并创建新的R1'的事件处理程序。这些是随机发生的,仅执行一次。我考虑了两种情况。第一个:
R1已在主线程中运行。
R2到达并排队在主线程中。
R1完成运行并再次发布。
R2运行并删除R1的回调。
R1永远不会再运行。
第二个:
R1未运行但已调度。
R2到达并删除R1的回调。
R1永远不会再运行。
从理论上讲,如果没有前提条件,并且只有一个线程,那么为什么有时主线程中会有两个R1?
最佳答案
由于您在selfStart或selfCancel上没有同步,因此这完全有可能。
在运行方法中的if语句检查了selfCancel
的值之后,可以在单独的线程上调用cancelled
,这是一个无关紧要的注释。然后MyRunnable
将再有一个调用来运行,由于已被取消,该调用将立即结束。