本文介绍了将任务提交到线程池会产生 RejectedExecutionException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一款在 Android NDK 中运行大部分原生代码的社交游戏.游戏有 3 个主要的 ndk pthreads:

I am working on a social game running mostly native code in Android NDK. The game has 3 main ndk pthreads:

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

除此之外,在 java 端,我们使用 AdWhirl,它通过自己的 ScheduledExecutorService 生成自己的线程,但我们已经包装了对schedule"、submit"、post"的每个调用, "start" 等使用 try-catch 块来捕获 RejectedExecutionException.然而,可怕的 RejectedExecutionException 仍然出现在我们提交的每个新版本上.

Other than that, on java side, we are using AdWhirl which spawns their own thread through their own ScheduledExecutorService, but we have wrapped every call to "schedule", "submit", "post", "start" etc with try-catch block to catch the RejectedExecutionException. However, the dreadly RejectedExecutionException still occurs on every new versions we submitted.

Android Market 的堆栈跟踪几乎没有给我留下任何线索,我们的 QA 部门也发现很难查明问题,因为它在测试期间几乎没有发生(只有我们的用户报告了崩溃).它只影响我们的一小部分用户,但每周仍有超过 7,000 次崩溃(与大量安装基数相比,这是一小部分)

The stack trace from Android Market leaves hardly any more clues for me and our QA department also find it difficult to pinpoint the problem as it hardly occur during test (only our users reported crash). It affects only a small portion of our users but still it is more than 7,000 crashes per week (small portion compared with high number of install base)

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)

推荐答案

虽然您当然应该尽量保持效率,但您允许"运行的线程数没有任意限制,它一切都取决于您如何构建代码.

While you should of course try to keep things as efficient as possible, there is no arbitrary limit to the number of threads you are "allowed" to run, it all depends on how you structure your code.

ThreadPoolExecutor非常有据可查,是您看到的问题的根源.我会推荐通读,看看

The ThreadPoolExecutor class is extremely well documented, and is where the issue you're seeing is originating. I would recommend reading through it, check out

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

To start with I'm guessing that you're building this with Ant and aren't using these parameters on your javac node:

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

无论是那个还是您显然使用的混淆器都是堆栈跟踪中通常最重要的部分只是简单地输出的原因:

Either that or the obfuscator you are apparently using are the reason that what would normally be the most important part of a stack trace is instead simply outputting:

c.onProgressUpdate(Unknown Source)

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

This is the current ICS 4.0.4 source for ThreadPoolExecutor.AbortPolicy, as you can see it's basically a catch-all that always throws an exception:

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

此外,您会发现在 ThreadPoolExecutor 顶部声明的 defaultHandler:

Additionally, you'll find the defaultHandler declared at the top of ThreadPoolExecutor:

private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

最后,如果您查看 ThreadPoolExecutor 的默认构造函数:

So finally, if you look at the default Constructor for 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.

You'll see that it's instantiating itself using it's AbortPolicy class, which is its default RejectedExecutionHandler.

ThreadPoolExecutor 还包括其他几个您可以设置为默认的 RejectedExecutionHandler 子类,例如:

ThreadPoolExecutor also includes several other RejectedExecutionHandler subclasses that you could set as the default, such as:

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

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

The other 3 ThreadPoolExecutor constructors include a handler option, so you could either create an instance of it using a different handler, or create you're own subclass, similar to this:

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

这篇关于将任务提交到线程池会产生 RejectedExecutionException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 05:31