Java 主线:可运行性可以被抢占吗?
我有一个可运行实例,它在其Java 主线:可运行性可以被抢占吗?,java,android,thread-safety,runnable,android-handler,Java,Android,Thread Safety,Runnable,Android Handler,我有一个可运行实例,它在其run方法的末尾再次自我调度自己: private class MyRunnable implements Runnable { private volatile boolean cancelled = false; private Handler handler; public MyRunnable(Handler h){ handler = h; }
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首先调度在主线程中,从活动的onStart
调用selfStart
同时,可以从活动的顶部和广播接收器外部取消运行(调用selfCancel
)
AFAIKRunnable.run
、Activity.onStop
和BroadcastReceiver.onReceive
在同一个线程(主线程)中运行,所以乍一看我认为不会有线程安全问题
但有时看起来,RunnEnter正处于其<>代码>运行调用的中间,然后从活动或接收器中取消,然后恢复并重新调度自身。
这可能吗
更新:
我会尽力更好地解释这个问题。上面显示的类用于在主线程中定期运行任务。在“do stuff”注释中,实际上有一段代码用传递给MyRunnable
构造函数的值更新TextView
。该活动取消当前runnable,并在收到特定意图时启动一个新的runnable。尽管在创建新的runnable之前,始终会请求当前runnable自身取消,但有时它会与新的runnable一起运行,因此文本视图会显示交替值。这不是预期的行为
我认为如果runnable当前在主线程中运行,它将一直运行到完成,然后其他runnable或事件处理程序将从队列中取出并在需要时执行,但不能“半执行”挂起的事件或runnable
主线程中运行的两种任务与问题相关:
- R1:
MyRunnable
自调度任务。运行,然后以1s的延迟再次自我发布
- R2:请求取消当前
MyRunnable
实例并创建新R1'的事件处理程序。这些操作随机发生,只执行一次
我考虑过两种情况。第一个:
R1已在主线程中运行
R2到达并在主线程中排队
R1完成运行并再次发布自己
R2运行并删除R1的回调
R1不应再次运行
第二个:
R1未运行,但已安排
R2到达并删除R1的回调
R1不应再次运行
从理论上讲,如果没有抢占,并且只有一个线程,为什么有时主线程中会有两个R1s?因为在selfStart或selfCancel上没有同步,这是完全可能的
在run方法中的if语句检查了cancelled
的值后,可以在单独的线程上调用未报告的注释selfCancel
MyRunnable
然后会得到另一个运行调用,该调用将在取消后立即结束。我的建议是将//Do stuff
移动到已取消的检查中
这就避免了竞争,而不考虑运行线程的假设
@Override
public void run(){
if(!cancelled){
//Do stuff
handler.post(this);
}
}
一般来说,为了便于维护,无论在哪个线程上运行,都要尝试编写能够正常工作的代码。你永远不知道什么时候会有人在其他线程上调用selfCancel(),你认为这是可以的,而你却认为他们不会这样做。正如其他人所说,在单个线程中不可能抢占runnable。我也觉得这个想法很荒谬。真为我想出那样的废话感到羞耻
runnables一家自己也没什么问题。它们在活动的启动
中启动,并从活动收到的意图或活动的启动
中取消。这是问题的根源:假设onStart
和onStop
将以可预测的顺序运行。有时,当返回到活动时,在第一个活动的启动之前执行第二个启动
。两个任务正在运行,事情搞砸了,第一个任务从未终止
确保在未终止当前任务之前不会启动任何任务解决了此问题。如果您只将Runnable发布到一个活套,那么您所描述的是不可能的。您如何知道Runnable在您标记的行上被抢占?它是否可能执行handler.post(这个)然后结束当前的运行?@user3118604我不认为它被抢占了,这是我能找到的唯一可能的解释,当只有一个线程时。但是听起来很牵强,我甚至不想相信这是可能的。在线程上运行的方法可能会被该线程上的其他东西抢先的想法很难相信。更合理的可能是,每个方法一开始就运行到完成,比该线程上的任何其他方法都要早,但要调用的方法队列并没有按照您期望的方式进行管理。记录每个方法的输入和返回及其tid应该提供洞察-在当前方法返回之前,您不应该在线程上看到新方法开始。虽然如果涉及多个线程,这将是正确的,但这并不是对所问问题的真正有意义的回答,除非您解释为什么这些代码中的一些会在主/UI线程以外的线程上运行。没有单独的线程。正在主线程中调用所有计划或取消。这些方法上的同步不会有太大变化,因为当应用程序启动时,selfStart
只被调用一次。有问题的方法是selfCancel
和run
。我想运行时会调用selfCancel