java - 主线程: can runnables be preempted?

标签 java android thread-safety runnable android-handler

我有一个可运行的实例,它在其 run 方法结束时再次 self 调度:

    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);
        }
    }

可运行对象首先在主线程中调度,从 Activity 的 onStart 调用 selfStart

同时,可以从 Activity 的 onStop 以及广播接收器外部取消可运行对象(调用 selfCancel)。

AFAIK Runnable.runActivity.onStopBroadcastReceiver.onReceive 在同一个线程(主线程)中运行,所以一开始乍一看我以为不会有线程安全问题。

但有时,可运行对象在其 run 调用过程中被抢占,然后从 Activity 或接收器中取消,然后再次恢复并重新调度自身。

这可能吗?


更新:
我会尽力更好地解释这个问题。上面显示的类旨在在主线程中定期运行任务。在“do stuff”注释中,实际上有一些代码使用传递给 MyRunnable 构造函数的值来更新 TextView。当收到某些 Intent 时,该 Activity 会取消当前的可运行状态并启动一个新的可运行状态。尽管当前的可运行对象总是被要求在创建新的可运行对象之前取消自身,但有时它会与新的可运行对象一起运行,因此 TextView 会显示交替值。这不是预期的行为。

我认为如果可运行对象当前正在主线程中运行,它将运行直到完成,然后其他可运行对象或事件处理程序将从队列中取出并在需要时执行,但不会有挂起的事件或可运行对象“执行了一半”。

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

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

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

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

第二个:

  1. R1 未运行,但已安排。
  2. R2 到达并删除 R1 的回调。
  3. R1 不应再次运行。

理论上,如果没有抢占,并且只有一个线程,为什么有时主线程中有两个R1?

最佳答案

由于您在 selfStart 或 selfCancel 上没有同步,所以这是完全有可能的。

一个不相关的注释,在 run 方法中的 if 语句检查了 cancelled 的值之后,可以在单独的线程上调用 selfCancel。然后,MyRunnable 将再获得一次运行调用,该调用将在被取消后立即结束。

关于java - 主线程: can runnables be preempted?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21438939/

相关文章:

c# - 在线程中打开新的子表单

c - PortAudio 回调,并在别处更改变量

android - 替换 fragment 时清除 fragment 添加的工具栏菜单选项

java - 访问 Android 媒体流以进行音频可视化

c# - 是否有等效于 C#'s ' checked' 关键字的 Java?

java - Android:解析 XML DOM 解析器。将子节点转换为字符串

Android ListView 褪色边缘

java - 从多线程设置和更新并发 HashMap

java - 循环遍历方向

java - swagger中spring fox health路由显示多个HTTP方法