【问题标题】:Binder thread interrupt unexpected behaviorBinder 线程中断意外行为
【发布时间】:2014-08-14 04:43:49
【问题描述】:

Android ContentProviders 使用“绑定线程”池来处理 RPC,例如 queryinsertcall。在我对ContentProvider 的实现中,我正在执行一个可以使用Thread#interrupt() 中断的长时间运行的任务。我写了一个看门狗线程,在某些情况下会中断当前正在执行的绑定线程。中断正确生效,但现在我注意到当 android 再次使用它来处理新的 RPC 时,binder 线程仍然设置了它的中断标志。这会导致新的 RPC 表现得好像它被中断了一样。我没想到会这样。我捕捉到了InterruptedException,但如果看门狗线程在 RPC 结束时设置了中断标志,而没有任何东西查看或清除标志,就会发生这种情况。

ExecutorService 的一些特别测试表明,当它重用线程来处理任务时,它会在运行每个任务之前的某个时间重置中断标志。我在ThreadPoolExecutor 类中找到了这条评论:

 * 2. Before running any task, the lock is acquired to prevent
 * other pool interrupts while the task is executing, and
 * clearInterruptsForTaskRun called to ensure that unless pool is
 * stopping, this thread does not have its interrupt set.

为了纠正 android 的行为,我认为在每个 ContentProvider RPC 开始时,我会使用 Thread.interrupted() 清除中断标志,但这似乎不是最优雅的解决方案。

谁能确认 android binder 线程实际上处理线程中断的方式是否与 ExecutorService 不同,以及最好的解决方法是什么,这样中断标志就不会在不同的 RPC 之间传播?

这里有一些代码可以放在ContentProvider 中以重现问题:

@Override
public Bundle call(String method, String arg, Bundle extras) {
  Log.w(TAG, "Thread "+ Thread.currentThread().getName() + " before isInterrupted()=" + Thread.currentThread().isInterrupted());

  final Thread callThread = Thread.currentThread();

  if (method.equals("interrupt")) {
    new Thread("interrupter") {
      @Override
      public void run() {
        callThread.interrupt();
      }
    }.start();
  }

  try {
    Thread.sleep(500);
  } catch (InterruptedException e) {
    Log.w(TAG, e);
    Thread.currentThread().interrupt();
  }

  Log.w(TAG, "Thread "+ Thread.currentThread().getName() + " after isInterrupted()=" + Thread.currentThread().isInterrupted());

  return null;
}

然后在Activity 中(确保它在与ContentProvider 不同的进程中运行!)连接两个按钮,一个执行常规调用,一个执行将触发中断的调用:

findViewById(R.id.call).setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
    getContentResolver().call(CallContentProvider.CONTENT_URI, "", "", null);
  }
});

findViewById(R.id.callint).setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
    getContentResolver().call(CallContentProvider.CONTENT_URI, "interrupt", "", null);
  }
});

【问题讨论】:

  • 你能让我们看看你的代码吗?从阅读中很难分辨。
  • 我添加了一些代码sn-ps,可以用来演示问题。

标签: android multithreading android-binder


【解决方案1】:

所以这是我迄今为止解决这个问题的最佳方法:

private volatile Thread mRunningCallThread;

@Override
public Bundle call(String method, String arg, Bundle extras) {
    Thread.interrupted(); // Clear interrupted flag

    mRunningCallThread = Thread.currentThread(); // Thread to interrupt

    // Do stuff, allowing interruption by another thread

    mRunningCallThread = null;

    Thread.interrupted(); // Clear interrupted flag
}

mRunningCallThread 字段是指向当前正在运行的线程的指针,我可能会中断它。

【讨论】:

    猜你喜欢
    • 2019-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    • 2021-08-25
    • 1970-01-01
    相关资源
    最近更新 更多