前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于ThreadPoolExecutor要注意的问题

关于ThreadPoolExecutor要注意的问题

作者头像
PhoenixZheng
发布2018-08-07 16:43:41
2530
发布2018-08-07 16:43:41
举报

之前我们说过关于线程池的问题,我们可以用Executors的各种方法来获取不同的ThreadPoolExecutor来满足需求。但是当我们需要自定义线程池的时候需要注意些什么呢?

ThreadPoolExecutor的参数含义

ThreadPoolExecutor的构造方法有几个用的多的参数,它们的含义分别是 · corePoolSize:线程池的基本大小 · maximumPoolSize:当任务队列满时允许扩展到的线程池的线程数量 · workQueue:存放任务队列的BlockingQueue · handler:当任务队列满时的处理策略

之前说过可以给AsyncTask指定线程池,我们用不同的参数构造线程池来验证效果。

LinkedBlockingQueue
public class DemoAsyncTask extends AsyncTask {
    private static final String TAG = "DemoAsyncTask";
    private static BlockingQueue<Runnable> blockingQueue = new LinkedBlockingDeque<>(3);

    private static Executor threadPoolExecutor = new ThreadPoolExecutor(3, 3, 0,
            TimeUnit.MICROSECONDS, blockingQueue);

    @Override
    protected Object doInBackground(Object[] objects) {
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Log.d(TAG, "doInBackground: num: " + objects[0]);
        return null;
    }

    public void demoExecute(String... params) {
        this.executeOnExecutor(threadPoolExecutor, params);
    }
}

指定一个LinkedBlockingQueue给线程池,然后我们从外部调用,

for(int i = 0; i < 50; i ++) {
  new DemoAsyncTask().demoExecute(String.valueOf(i));
}

这段代码运行就会崩溃,原因是

我们给线程池分配了50个任务,但是任务队列最大只能存放3个任务,当队列满时,系统会抛出RejectedExecutionException异常

解决这个问题有两种方法,一种是不给LinkedBlockingQueue指定队列大小。因为默认情况下 LinkedBlockingDeque会让队列不断增长以存放新进来的数据。这种方式能让50个任务正常进行。

另外一种是用 handler 参数指定队列满时的处理策略,代码可以改成下面这样

private static Executor threadPoolExecutor = new ThreadPoolExecutor(3, 3, 0,
        TimeUnit.MICROSECONDS, blockingQueue, new ThreadPoolExecutor.DiscardOldestPolicy());

这是ThreadPoolExecutor的其中一个默认策略,我们直接看输出就明白了,

04-19 12:42:35.991 6167-6199/com.phoenix.mkdirdemo D/DemoAsyncTask: doInBackground: num: 2 04-19 12:42:35.991 6167-6198/com.phoenix.mkdirdemo D/DemoAsyncTask: doInBackground: num: 1 04-19 12:42:35.991 6167-6196/com.phoenix.mkdirdemo D/DemoAsyncTask: doInBackground: num: 0 04-19 12:42:36.991 6167-6199/com.phoenix.mkdirdemo D/DemoAsyncTask: doInBackground: num: 47 04-19 12:42:36.991 6167-6198/com.phoenix.mkdirdemo D/DemoAsyncTask: doInBackground: num: 48 04-19 12:42:36.991 6167-6196/com.phoenix.mkdirdemo D/DemoAsyncTask: doInBackground: num: 49

所以就是说,这个策略会把队列里老的请求丢弃,保留最新请求。因为一开始的任务0-2正在执行中,而队列已满,因此最终只能保留47-49最后三个请求。这个策略适合用在fast fail场景,快速的反馈给用户失败而不是让用户等待。

ArrayBlockingQueue

用 ArrayBlockingQueue会有个问题,因为它的存储方式是数组,需要一开始就指定大小,所以必须得指定 handler来做队列满时的处理策略。 如果不指定handler的话只要任务数量超过 ArrayBlockingQueue 指定的大小,就会抛出 RejectedExecutionException异常。

回到 AsyncTask

其实 AynscTask 默认会有个线程池,这个线程池的大小是128,可以从源码看出来

private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

所以如果用默认的AsyncTask来处理大量的任务的话是有可能导致应用崩溃的。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android每日一讲 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ThreadPoolExecutor的参数含义
  • LinkedBlockingQueue
  • ArrayBlockingQueue
  • 回到 AsyncTask
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档