Android没有正确处理Executor中的AssertionError?

时间:2014-09-04 19:47:48

标签: java android exception threadpoolexecutor

我的测试表明Android在Executor线程中抛出时会默默地忽略AssertionError。在logcat中没有打印任何内容,应用程序也不会崩溃。这似乎是错的,其他人是否也能够重现这一点?知道为什么会这样,或者有办法解决或修复?

这是我的测试:

public class TestActivity extends Activity {

  private final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    exec.execute(new Runnable() {
      @Override
      public void run() {
        System.err.println("about to fail");
        if (true ) throw new AssertionError();
      }
    });
  }
}

2 个答案:

答案 0 :(得分:0)

这不仅仅是Android;这是(恼人的)沼泽标准的Java行为。 runnable抛出未捕获异常的ExecutorService线程只是在没有记录的情况下终止。

最简单的解决方法是将Executors包装成这样 - 您可以手动执行此操作,也可以创建一个替代而不是库存的替换ExecutorService:

public class PrintingExecutor implements ExecutorService {
  private final ExecutorService mDelegate;

  public PrintingExecutor (ExecutorService pDelegate) {
    mDelegate = pDelegate;
  }

  @Override
  public Future<?> submit(Runnable task) {
    return mDelegate.submit (new PrintingRunnable(task));
  }

  //override the rest of Executor's methods

  private static class PrintingRunnable implements Runnable {
    private final Runnable mDelegate; 
    public PrintingRunnable (Runnable toRun) {
      mDelegate = toRun;
    }

    @Override
    public void run () {
      try {
        mDelegate.run();
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }
  } 
}

答案 1 :(得分:0)

我认为这个问题与Exception handling in ThreadPoolsHow to properly catch RuntimeExceptions from Executors?

重复

所以我想我明白现在发生了什么。这不是Android特定的问题,它是通用Java。该问题与您在服务上安排任务的方式有关。

如果使用execute,则运行时异常将停止服务线程,VM将通过打印堆栈跟踪并停止整个过程来处理(除非您使用Scheduled执行程序,否则进一步了解。)

如果您使用submit,则会返回Future,当您在get()上致电Future时,它会抛出java.util.concurrent.ExecutionException,您可以检查看看发生了什么。在这种情况下,服务会保留处理任务。

因此,如果您要使用get(),或仅使用Future,则必须确保在submit上致电execute()

<强>无论其

Executors.newSingleThreadScheduledExecutor()Executors.newSingleThreadExecutor)不同。 Scheduled执行程序带来了进一步的复杂化,因为它会在线程死亡时重新启动线程并且它会以静默方式执行。因此,在这种情况下,您需要打包Runnable as suggested in this answer

以下是一些展示差异的代码:

  private final ScheduledExecutorService service = Executors.newSingleThreadExecutor();

  public static void testExecuteBomb(ExecutorService service) {
    service.execute(new Runnable() {
      @Override
      public void run() {
        printWithMillis("execute bombing...");
        if (true) throw new RuntimeException("Bomb");
      }
    });

    sleep();

    service.shutdownNow();
  }

  public static void testSubmitBomb(ExecutorService service) {
    try {
      Future t = service.submit(new Runnable() {
        @Override
        public void run() {
          printWithMillis("submit bombing...");
          if (true) throw new RuntimeException("Bomb");
        }
      });

      sleep();

      try {
        printWithMillis(String.valueOf(t.get()));
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    } finally {
      service.shutdownNow();
    }
  }