将任务提交给线程池会产生RejectedExecutionException

Zen*_*aro 17 multithreading android android-ndk

我正在开发一款社交游戏,主要运行Android NDK中的本机代码.该游戏有3个主要的ndk pthreads:

  1. 一个游戏线程
  2. 服务器通信线程
  3. 主渲染线程(通过Renderer.onRender调用)

除此之外,在java方面,我们正在使用AdWhirl,它通过自己的方式生成自己的线程ScheduledExecutorService,但我们用try-catch块将每个调用包装到"schedule","submit","post","start"等.抓住了RejectedExecutionException.但是,RejectedExecutionException我们提交的每个新版本都会出现这种情况.

来自Android Market的堆栈跟踪几乎没有给我留下任何线索,我们的质量保证部门也发现难以确定问题,因为它在测试期间几乎不会发生(只有我们的用户报告崩溃).它仅影响我们用户的一小部分但仍然每周超过7,000次崩溃(小部分与大量安装基础相比)

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)
Run Code Online (Sandbox Code Playgroud)

Jus*_*ser 17

虽然您当然应该尽量保持高效,但是"允许"运行的线程数没有任意限制,这完全取决于您构建代码的方式.

ThreadPoolExecutor课程记录非常详细,是您所看到的问题的起源.我建议通读它,看看

首先,我猜测你是用Ant构建的,并且没有在你的javac节点上使用这些参数:

<javac debug="true" debuglevel="lines,vars,source" />
Run Code Online (Sandbox Code Playgroud)

您或者显然正在使用的混淆器是通常最重要的堆栈跟踪部分而不是输出的原因:

c.onProgressUpdate(Unknown Source)
Run Code Online (Sandbox Code Playgroud)

这是ThreadPoolExecutor.AbortPolicy的当前ICS 4.0.4源代码,因为您可以看到它基本上是一个总是抛出异常的全能:

 /**
 * 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());
    }
}
Run Code Online (Sandbox Code Playgroud)

另外,你会发现在ThreadPoolExecutor顶部声明的defaultHandler:

private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
Run Code Online (Sandbox Code Playgroud)

最后,如果你看一下ThreadPoolExecutor的默认构造函数:

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

你会看到它使用它的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) {
    }
}
Run Code Online (Sandbox Code Playgroud)

其他3个ThreadPoolExecutor构造函数包含一个处理程序选项,因此您可以使用不同的处理程序创建它的实例,或者创建自己的子类,类似于:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Ren*_*eno 13

你必须检查你的代码,它创建的AsyncTask太多了.

政策设定为

private static final int CORE_POOL_SIZE = 1;
private static final int MAXIMUM_POOL_SIZE = 10;
private static final int KEEP_ALIVE = 10; 
Run Code Online (Sandbox Code Playgroud)

注意:这在Android的不同版本中有所不同

  • 请小心,不要将线程池大小与队列大小混淆.threadpoolsize是一次可以运行以服务队列的最大线程数.队列大小是队列可以获得的长度.导致被拒绝的执行异常的原因是队列大小,而不是池大小.从2.1开始,队列大小确实是10,尽管池大小实际上是128:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.1_r2/android /os/AsyncTask.java (4认同)