Отправка задач в пул потоков дает RejectedExecutionException - PullRequest
17 голосов
/ 17 октября 2011

Я работаю над социальной игрой, в которой в основном Android-NDK.В игре есть 3 основных направления:

  1. игровой поток
  2. коммуникационный поток сервера
  3. основной поток рендеринга (вызываемый через Renderer.onRender)

Кроме этого, на стороне java мы используем AdWhirl, который порождает их собственный поток через их ScheduledExecutorService, но мы обернули каждый вызов "schedule", "submit", "post", "start "и т. д. с блоком try-catch, чтобы поймать RejectedExecutionException.Тем не менее, ужасный RejectedExecutionException все еще возникает в каждой новой представленной нами версии.

Трассировка стека с Android Market вряд ли даст мне больше подсказок, и нашему отделу контроля качества также сложно определить проблему, так как вряд липроисходят во время теста (только наши пользователи сообщили о сбое).Это влияет только на небольшую часть наших пользователей, но все же это более 7000 сбоев в неделю (небольшая часть по сравнению с большим количеством установочной базы)

java.util.concurrent.RejectedExecutionException
at         java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1876)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:774)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1295)
at android.os.AsyncTask.execute(AsyncTask.java:394)
at c.onProgressUpdate(Unknown Source)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:432)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4632)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)

    java.util.concurrent.RejectedExecutionException: pool=128/128, queue=10/10
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1961)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:794)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1315)
at android.os.AsyncTask.execute(AsyncTask.java:394)
at c.onProgressUpdate(Unknown Source)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:432)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605)
at dalvik.system.NativeStart.main(Native Method)

    java.util.concurrent.RejectedExecutionException
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1876)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:774)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1295)
at android.os.AsyncTask.execute(AsyncTask.java:394)
at c.onProgressUpdate(Unknown Source)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:432)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)

Ответы [ 3 ]

17 голосов
/ 24 июня 2012

Хотя вы, конечно, должны стараться поддерживать максимальную эффективность, произвольного ограничения на количество потоков, которые вам «разрешено» запускать, нет, все зависит от того, как вы структурируете свой код.

Класс ThreadPoolExecutor чрезвычайно хорошо документирован, и именно здесь возникает проблема, с которой вы сталкиваетесь.Я бы рекомендовал прочитать его , посмотрите

Для начала я предполагаю, что вы строите это с помощью Ant и не используете эти параметры на своем узле javac:

<javac debug="true" debuglevel="lines,vars,source" />

Или тот или другой обфускатор, который вы, по-видимому, используете, являются причиной того, что то, что обычно является самой важной частью трассировки стека, вместо этого просто выводит:

c.onProgressUpdate(Unknown Source)

Это текущийИсходный код ICS 4.0.4 для ThreadPoolExecutor.AbortPolicy, как вы можете видеть, это в основном универсальное средство, которое всегда выдает исключение:

 /**
 * A handler for rejected tasks that throws a
 * {@code RejectedExecutionException}.
 */

public static class AbortPolicy implements RejectedExecutionHandler {
    /**
     * Creates an {@code AbortPolicy}.
     */
    public AbortPolicy() { }

    /**
     * Always throws RejectedExecutionException.
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     * @throws RejectedExecutionException always.
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " +
                                             e.toString());
    }
}

Кроме того, вы найдете defaultHandler, объявленный в верхней части ThreadPoolExecutor:

private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

Итак, наконец, если вы посмотрите на конструктор по умолчанию для ThreadPoolExecutor:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         threadFactory, defaultHandler);
}

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

ThreadPoolExecutor также включает несколько других RejectedExecutionHandler подклассов, которые вы можете установить по умолчанию, например:

  /**
 * A handler for rejected tasks that silently discards the
 * rejected task.
 */
public static class DiscardPolicy implements RejectedExecutionHandler {
    /**
     * Creates a {@code DiscardPolicy}.
     */
    public DiscardPolicy() { }

    /**
     * Does nothing, which has the effect of discarding task r.
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
}

Другие 3ThreadPoolExecutor конструкторы включают опцию обработчика, так что вы можете либо создать ее экземпляр, используя другой обработчик, либо создать свой собственный подкласс, подобный этому:

package com.justinbuser;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class NoThrowThreadPool extends ThreadPoolExecutor {

    private static final RejectedExecutionHandler defaultHandler = new AdoptPolicy();

    public NoThrowThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler);
        setRejectedExecutionHandler(defaultHandler);
    }

    public NoThrowThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,
            ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler);
    }

    public NoThrowThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,
            RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler);
    }

    public NoThrowThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,
            ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler);
    }

    public static class AdoptPolicy extends ThreadPoolExecutor.AbortPolicy {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()).printStackTrace();
        }
    }
}
13 голосов
/ 17 октября 2011

Вам придется проверить свой код, он создает слишком много AsyncTask, чем ему разрешено.

Политика установлена ​​на

private static final int CORE_POOL_SIZE = 1;
private static final int MAXIMUM_POOL_SIZE = 10;
private static final int KEEP_ALIVE = 10; 

Примечание: это зависит от версии Android

0 голосов
/ 25 марта 2013

Новые задачи, представленные в методе execute (java.lang.Runnable), будут отклонены, когда исполнитель выключен, а также когда исполнитель использует конечные границы как для максимальных потоков, так и для емкости рабочей очереди, и насыщается.

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/ThreadPoolExecutor.java

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...