主线程:可以抢占运行吗?

时间:2014-01-29 17:58:51

标签: 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;
        }


        @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.runActivity.onStopBroadcastReceiver.onReceive在同一个主题(主要主题)中运行,所以乍一看我认为不存在线程安全问题。

但看起来有时候,runnable正在其run调用的中间被删除,然后它从活动或接收器中被取消,然后它重新开始并重新安排自己。

这可能吗?


更新:
我会尝试更好地解释这个问题。上面显示的类旨在定期在主线程中运行任务。在"做东西"在那里发表评论的实际代码是使用传递给TextView构造函数的值更新MyRunnable。活动取消当前的runnable,并在收到某些意图时启动新的runnable。尽管当前runnable总是被请求在创建新的runnable之前取消它,但有时它会与新的一起运行,因此文本视图显示交替的值。这不是预期的行为。

我认为如果runnable当前在主线程中运行,它将一直运行直到完成,然后其他runnables或事件处理程序将从队列中取出并在需要时执行,但是没有挂起事件或runnable可能是& #34;一半执行"。

主线程中运行的任务有两种与问题相关的任务:

  • R1:MyRunnable自我调度任务。运行然后再以1s的延迟自我发布。
  • R2:请求取消当前MyRunnable实例并创建新R1'的事件处理程序。这些都是随机发生的,只执行一次。

我考虑过两种情况。第一个:

  1. R1已在主线程中运行。
  2. R2到达并在主线程中排队。
  3. R1完成运行并再次发布。
  4. R2运行并删除R1的回调。
  5. R1不应该再次运行。
  6. 第二个:

    1. R1未运行但已安排。
    2. R2到达并删除R1的回调。
    3. R1不应该再次运行。
    4. 理论上,如果没有预设,并且只有一个线程,那么主线程中有时会有两个R1?

3 个答案:

答案 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中取消。这是问题的根源:假设onStartonStop将以可预测的顺序运行。有时回到活动时,在第一个活动的onStart之前执行了第二个onStop。两个任务正在运行,事情搞砸到第一个任务永远不会终止的地步。

确保在没有先前终止任务的情况下没有启动任务解决了问题。