RejectedExecutionException из AsyncTask, но не ударил пределы

Мое Android-приложение должно иметь дело с поступающими сообщениями, которые часто бывают в пучках (особенно в периоды щекотливой связи). Я обрабатываю эти входящие сообщения в AsyncTasks, чтобы я не вмешивался в поток пользовательского интерфейса. Если сразу приходит слишком много сообщений, я получаю RejectedExecutionException. Мой стек ошибок выглядит следующим образом:

10-22 14:44:49.398: E/AndroidRuntime(17834): Caused by: java.util.concurrent.RejectedExecutionException: Task [email protected] rejected from [email protected][Running, pool size = 128, active threads = 22, queued tasks = 0, completed tasks = 1323]
10-22 14:44:49.398: E/AndroidRuntime(17834):    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1967)
10-22 14:44:49.398: E/AndroidRuntime(17834):    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:782)
10-22 14:44:49.398: E/AndroidRuntime(17834):    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1303)
10-22 14:44:49.398: E/AndroidRuntime(17834):    at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:564)

Я запускаю задачи с task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR), чтобы поступающие сообщения обрабатывались параллельно.

Что сбивает с толку об этом и отличается от связанных вопросов StackOverflow, которые я могу найти (например, здесь и здесь) состоит в том, что количество активных потоков и задач в очереди не похоже на то, что они сталкиваются с ограничениями (которые, как представляется, составляют 128 и 10 соответственно). Смотрите stacktrace:

[email protected][Running, pool size = 128, active threads = 22, queued tasks = 0, completed tasks = 1323]

Почему я должен получать это сообщение об ошибке?

Ответ 1

Почему я должен получать это сообщение об ошибке?

Вы получите это сообщение об ошибке, если вы превысили количество задач, которые могут быть поставлены в очередь с помощью ThreadPoolExecutor. Единственный раз, когда бросается RejectedExecutionException, является ThreadPoolExecutor.AbortPolicy, который является значением по умолчанию RejectedExecutionHandler.

Для цитаты из javadocs:

Если запрос не может быть поставлен в очередь, создается новый поток, если это не будет превышать maximumPoolSize, и в этом случае задача будет отклонена.

Максимальное количество задач. См. Этот вопрос/ответ здесь: Есть ли предел AsyncTasks для выполнения одновременно?

Здесь ссылка для исходного кода для AsyncTask.

private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;

private static final BlockingQueue<Runnable> sWorkQueue =
        new LinkedBlockingQueue<Runnable>(10);

private static final ThreadPoolExecutor sExecutor =
    new ThreadPoolExecutor(CORE_POOL_SIZE,
        MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);

Итак, похоже, что он начинается с 5 потоков, имеет очередь 10. После того, как очередь заполнена, она может запустить до 128 потоков. Таким образом, похоже, что вы превысили 138 одновременных запросов.

ThreadPoolExecutor @412716b8 [Running, pool size = 128, active threads = 22, queued tasks = 0, завершенные задачи = 1323]

Попытка поймать ThreadPoolExecutor точный момент, когда он закончится, будет очень тяжелым, и он быстро превратится в heisenbug, поскольку чем больше вы смотрите на цифры ThreadPoolExecutor, тем больше вы будете влиять на синхронизацию этого класса, и поэтому вы можете сделать ошибку.

В вашем случае, к тому моменту, когда вы получите сообщение об исключении с подробной информацией о TPE, условие должно было пройти.

Ответ 2

Это исключение также возникает, если ваш метод выключения Executor вызывается, и после этого вы даете новую задачу (Runnable) для выполнения. Как

mThreadPoolExecutor.shutdown();
...
...
...
mThreadPoolExecutor.execute(new Runnable(){...});