Android多线程之线程池Executor详解

本文介绍了Android中线程池Executor的重要性和优势,详细解析了ThreadPoolExecutor的构造参数,如核心线程数、最大线程数等。讨论了四种类型的线程池:FixedThreadPool、CachedThreadPool、ScheduledThreadPool和SingleThreadExecutor的工作原理和使用场景,并通过示例展示了它们的行为特点。
摘要由CSDN通过智能技术生成

前言:前面说过,Android系统延续了Java的单线程设计模型,因此在开发过程中经常会去开辟新的线程,去处理与UI操作无关的任务。线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,不能无限制的产生,它的创建与销毁都会产生较多的系统开销。因此,为了方便线程的管理,Android提供了线程的管理机制-Executor线程池。

这里简单复习一下,Android在UI线程进行耗时任务出现ANR的几种情况:

  1. Activity在5秒钟内无法响应屏幕触摸事件或键盘输入事件。
  2. BroadcastReceiver在10秒内没有执行完操作。

同样,Android实现多线程的方式很多这里简单总结一下:

  1. 通过继承Thread类实现多线程(通过Handler消息通信机制和UI线程通信)。
  2. 通过Android内部封装类AsyncTask实现多线程(封装了线程池和Handler)。
  3. 通过IntentService实现多线程(内部采用HandlerThread执行任务)。
  4. 通过HandlerThread实现多线程。

上面的都不是我们今天的重点,在这里就不详细分析了,网上也有很多关于它们的用法,有兴趣的可以去找一下。接下来我们郑重认识一下Android线程池Executor:

首先我们介绍一下线程池的优势:

  • 重用线程池中的线程,避免因为现成的创建和销毁带来的性能开销。
  • 有效控制线程池的最大并发数,避免大量线程之间因为抢占系统资源而导致的阻塞现象。
  • 能对线程进行有效的管理,,并且便于控制线程的执行等功能。
  • 提高任务到来时的响应速度,有效提升效率。

我们都知道Android实现线程池都是通过配置ThreadPoolExecutor实现的,同时Android有四类不同的线程池,不同类型的线程池管理线程的策略也大不相同,我们需要综合衡量,选择最适合我们需求且能保证其执行效率的线程池,这就需要我们对ThreadPoolExecutor的配置了解的很清楚。

  1. 接下来我们看一下ThreadPoolExecutor的构造器,需要怎么去初始化一个ThreadPoolExecutor:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
                    TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { }
  • corePoolSize:线程池的核心线程数,默认会一直存活,即使它处于空闲的状态,除非你设置它的超时策略。
  • maximumPoolSize:线程池最大容纳线程数量,当任务数量大于最大线程数量时,后续的任务会被阻塞。
  • keepAliveTime:非核心线程的超时时长,找过这个时间后,非核心线程会被回收。核心线程设置了超时策略后,也会被回收。
  • unit:超时时长的单位。
  • workQueue:线程池中存储任务的任务队列,当有空闲线程的时候,就会从队列中取出任务去执行。
  • threadFactory:为线程池提供创建新线程的功能。

接下来,看一下ThreadPoolExecutor执行任务的流程:

  • 如果线程池中线程数量未达到核心线程数量,立即创建一个核心线程去执行任务。
  • 如果线程数达到了核心线程数量,而未达到设置的总线程数。那么会把当前任务插入到任务队列的队尾。
  • 如果任务队列已满,立即创建一个非核心线程去处理当前任务。
  • 如果任务队列已满,并且线程池中线程数量也达到了线程池容纳线程的最大数量,此时拒绝执行此任务。

线程池的分类:

  • FixedThreadPool:仅有核心线程的线程池(线程在空闲时不会被回收)。
    创建方式和示例用法:
 //设置线程池大小,Runtime.getRuntime().availableProcessors() + 1是当前核心线程数
        ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
        //这里设置任务个数为核心线程的3倍,如果按上述FixedThreadPool的定义所说,那么这里应该分3个批次打印出来
        int maxTaskCount = 3 * (Runtime.getRuntime().availableProcessors() + 1);
        for (int i = 0; i < maxTaskCount; i++) {
            final int finalI = i;
            service.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("currentTime:" + System.currentTimeMillis() + "-----" + "currentTask" + finalI);
                        //每间隔2秒打印一个批次的数据,一共分3批次
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
         try {
            Thread.sleep(5000);
            System.out.println("---------------------------------------");
            //在所有任务结束后,查看线程池线程是否被回收(获取活动的线程个数)
            System.out.println("currentThreadCount:" + ((ThreadPoolExecutor) service).getActiveCount());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
打印结果为:
03-12 10:22:56.219 13147-13159/com.hbandroid.testthreaddemo I/System.out: currentTime:1520821376224-----currentTask0
03-12 10:22:56.219 13147-13160/com.hbandroid.testthreaddemo I/System.out: currentTime:1520821376224-----currentTask1
03-12 10:22:56.223 13147-13161/com.hbandroid.testthreaddemo I/System.out: currentTime:1520821376225-----currentTask2
03-12 10:22:56.223 13147-13162/com.hbandroid.testthreaddemo I/System.out: currentTime:1520821376225-----currentTask3
03-12 10:22:56.223 13147-13163/com.hbandroid.testthreaddemo I/System.out: currentTime:1520821376225-----currentTask4
03-12 10:22:58.223 13147-13159/com.hbandroid.testthreaddemo I/System.out: currentTime:1520821378225-----currentTask5
03-12 10:22:58.223 13147-13160/com.hbandroid.testthreaddemo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值