ThreadPool,遇到有破坏性使用的时候,也不能让它沾满线程池,最多同时仅留一个线程为其服务。

遇到的问题:

12-30 18:43:57.442 +0800 16559 16559 E Zygote : java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask$3@2eb3071rejected from java.util.concurrent.ThreadPoolExecutor@30dfbd5[Running, pool size = 17, active threads = 17, queued tasks = 128, completed tasks = 303920]

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2078)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:843)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1389)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:651)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at com.android.server.OpsService$1.run(SmtOpsService.java:100)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at android.os.Handler.handleCallback(Handler.java:790)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at android.os.Handler.dispatchMessage(Handler.java:99)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at android.os.Looper.loop(Looper.java:164)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at com.android.server.SystemServer.run(SystemServer.java:456)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at com.android.server.SystemServer.main(SystemServer.java:289)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at java.lang.reflect.Method.invoke(Native Method)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)

12-30 18:43:57.442 +0800 16559 16559 E Zygote  : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:800)

AsyncTask.THREAD_POOL_EXECUTOR的queued task满了,pool size也超过了上限。原因是有一个第三方应用出现了异常,不停地死掉重启,导致在updateOom的时候反复设置其process group,把任务队列填满了,别的地方再向AsyncTask里面加任务时就崩了。


原来的代码:

void asyncSetProcessGroupAll (int uid, int pid, int processGroup) {

        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {

            @Override

            public void run() {

                try {

                    Process.setProcessGroupAll(uid, pid, processGroup);

                } catch (Exception e) {

                    Slog.w(TAG, "Failed setting process group of " + pid + " to " + processGroup, e);

                }

            }

        });

    }

修改的思路有两点,首先不用AsyncTask了,这东西毕竟是公共的,堵死了大家都受影响,自己单独搞一个线程池。

第二就是即使使用了自己的线程池,对这种有破坏性的应用也要进行约束。同时仅有一个线程为其服务。

修改后的代码:

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.LinkedBlockingQueue;

import java.util.concurrent.ThreadPoolExecutor;

import java.util.concurrent.TimeUnit;

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();

    // We want at least 2 threads and at most 4 threads in the core pool,

    // preferring to have 1 less than the CPU count to avoid saturating

    // the CPU with background work

    private static final int CORE_POOL_SIZE = 1;

    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT / 2;

    private static final int KEEP_ALIVE_SECONDS = 15;

    final ThreadPoolExecutor mThreadPoolExecutor =

                                  new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,

                                  KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,

                                  new LinkedBlockingQueue(15));

private class PGInfo {

        int uid;

        int processGroup;

        PGInfo(int uid, int processGroup) {

            this.uid = uid;

            this.processGroup = processGroup;

        }

    }

    private HashMap mPGMap = new HashMap<>();

    void asyncSetProcessGroupAll (int uid, int pid, int processGroup) {

        synchronized (mPGMap) {

            PGInfo info = mPGMap.get(pid);

            if (null == info) {

                info = new PGInfo(uid, processGroup);

                mPGMap.put(pid, info);

            } else {

                info.uid = uid;

                info.processGroup = processGroup;

                return;

            }

        }

        mThreadPoolExecutor.execute(new Runnable() {

            @Override

            public void run() {

                PGInfo info;

                int tmpUid, tmpProcessGroup;

                synchronized (mPGMap) {

                    info = mPGMap.get(pid);

                    tmpUid = info.uid;

                    tmpProcessGroup = info.processGroup;

                }

                while (true) {

                    try {

                        Process.setProcessGroupAll(tmpUid, pid, tmpProcessGroup);

                    } catch (Exception e) {

                        Slog.w(TAG, "Failed setting process group of " + pid + " to " + tmpProcessGroup, e);

                    } finally {

                        synchronized (mPGMap) {

                            if (tmpUid == info.uid && tmpProcessGroup == info.processGroup) {

                                mPGMap.remove(pid);

                                break;

                            } else {

                                tmpUid = info.uid;

                                tmpProcessGroup = info.processGroup;

                            }

                        }

                    }

                }

            }

        });

    }

你可能感兴趣的:(ThreadPool,遇到有破坏性使用的时候,也不能让它沾满线程池,最多同时仅留一个线程为其服务。)