trabajo trabajar tareas plataformas para organizar herramientas grupal gestor equipos equipo compartida colaborativo calendario apps app aplicaciones agenda android multithreading android-ndk

android - trabajar - herramientas de trabajo grupal



Enviar tareas a un grupo de subprocesos da RejectedExecutionException (3)

Estoy trabajando en un juego social que ejecuta principalmente código nativo en Android NDK. El juego tiene 3 pnreads principales de ndk:

  1. un hilo del juego
  2. un hilo de comunicación del servidor
  3. el hilo principal de renderizado (llamado a través de Renderer.onRender)

Aparte de eso, en java, estamos usando AdWhirl, que genera su propio hilo a través de su propio ScheduledExecutorService , pero hemos ajustado cada llamada a "programar", "enviar", "publicar", "comenzar", etc. con el bloque try-catch atrapar la RejectedExecutionException . Sin embargo, la espantosa RejectedExecutionException todavía ocurre en cada nueva versión que enviamos.

El seguimiento de la pila de Android Market no deja más pistas para mí y nuestro departamento de control de calidad también tiene dificultades para identificar el problema, ya que apenas ocurre durante la prueba (solo nuestros usuarios informaron fallas). Afecta solo a una pequeña parte de nuestros usuarios, pero aún así es más de 7.000 bloqueos por semana (una pequeña parte en comparación con una gran cantidad de bases de instalación)

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)


Deberá verificar su código, está creando demasiadas AsyncTask de lo que está permitido.

La política está configurada para

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

Nota: esto varía en las diferentes versiones de Android


Si bien deberías, por supuesto, tratar de mantener las cosas de la manera más eficiente posible, no hay un límite arbitrario para el número de subprocesos que tienes permitido ejecutar, todo depende de cómo estes estructurando tu código.

La clase ThreadPoolExecutor está extremadamente bien documentada, y es donde se origina el problema que está viendo. Yo recomendaría leerlo , echa un vistazo

Para empezar, supongo que estás creando esto con Ant y no estás usando estos parámetros en tu nodo javac:

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

O eso o el ofuscador que aparentemente está usando son la razón por la cual lo que normalmente sería la parte más importante de un seguimiento de pila, en cambio, simplemente está generando:

c.onProgressUpdate(Unknown Source)

Esta es la fuente actual de ICS 4.0.4 para ThreadPoolExecutor.AbortPolicy, como se puede ver, es básicamente un catch-all que siempre arroja una excepción:

/** * 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()); } }

Además, encontrará el valor predeterminado deHandler declarado en la parte superior de ThreadPoolExecutor:

private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

Entonces, finalmente, si miras el Constructor por defecto para ThreadPoolExecutor:

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

Verás que se está instanciando usando su clase AbortPolicy , que es su RejectedExecutionHandler predeterminado.

ThreadPoolExecutor también incluye varias otras subclases RejectedExecutionHandler que puede establecer como predeterminadas, como:

/** * 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) { } }

Los otros 3 constructores de ThreadPoolExecutor incluyen una opción de controlador, por lo que puede crear una instancia usando un controlador diferente o crear su propia subclase, similar a esto:

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