Android线程池

一、为什么要用线程池

目前就我在Android开发工作中,实际自己写线程用到线程池真的很少,但是又不得不去了解下线程池。线程池直白点就是管理线程的一个工具,平时我们创建子线程可能直接用Thread方法创建一个子线程就完事了。

Thread{
   //需要执行的耗时代码
}.start()

当然,如果是简单的单线程,不需要使用线程池的。牵扯多线程时推荐试用线程池,比如我们常见的多个文件同时下载。会牵扯到多个线程创建执行,如果处理不好,会导致大量线程创建和销毁,这样会造成资源浪费,使性能降低。这时候就需要用到线程池去管理线程

二、线程池原理

线程池是一个池子,里面能容纳多个线程。线程池帮助我们管理线程的创建、复用、销毁;具体啥时候创建,何时复用,什么时候销毁;需要根据ThreadPoolExecutor类的构造参数去实现

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

参数说明:

  • corePoolSize: 核心线程数量,存活情况有两种:1.当allowCoreThreadTimeout = flase (默认)时 ,核心线程会伴随线程池的整个生命周期一直存活;2.当allowCoreThreadTimeout = true 时,空闲时长超过 keepAliveTime设置的时长,会被销毁。
  • maximumPoolSize:最大线程数,可以理解为线程池容纳线程最大个数。
  • keepAliveTime:允许空闲时长,超出这个时长,非核心线程会被销毁(非核心线程 = maximumPoolSize - corePoolSize),核心线程会不会被销毁还需要看参数allowCoreThreadTimeout是否为true
  • unit:时间单位,与keepAliveTime参数有关
  • workQueue:任务队列,线程池中的线程没有空闲时,多余的任务会放任务队列中等待

下面代码是一个实例:

 val threadPoolExecutor =
            ThreadPoolExecutor(2, 4, 1, TimeUnit.SECONDS, LinkedBlockingQueue<Runnable>(6))
        findViewById<View>(R.id.btn5).setOnClickListener{
            for (i in 1..10) {
                threadPoolExecutor.execute{
                    Thread.sleep(3000)
                    Log.e("print","当前线程个数:$i, 线程名:${Thread.currentThread().name}")
                }
            }
        }

核心线程数为2,最大线程数为4,超时1秒,任务队列长度6个。任务总数10个
注意:这里有个公式(任务队列总数 + 最大线程数 >= 任务总数),这个公式必须成立,不然会报错java.util.concurrent.RejectedExecutionException

运行结果:

log1

等待几秒再运行for循环中代码打印日志

log2

分析日志1:
一共10个任务,程序会先创建2个核心线程去领2个任务执行,还剩下8个任务。而任务队列长度只有6,还有剩余两个任务没法放入,这时候就会创建非核心线程去执行这两个任务(这里允许最大线程数为4,已经创建了2个核心线程,刚好还可以创建2个非核心线程,也就是我前面说的那个公式必须成立,如果这里最大线程数小于4,就会报错)。看日志刚好一共创建了4条线程,后面的都是复用这4条线程去执行

分析日志2:
因为等待了几秒,超过了我们设置的超时时间1秒。线程池会回收两个非核心线程。从日志可以看出线程1和3被回收了(非核心线程),复用了线程2和4(核心线程),然后又创建了两个新的线程5和6

三、介绍几种常见线程池

  • Executors.newFixedThreadPool(2) 核心线程池,用此方法创建的线程池只有核心线程
  • Executors.newCachedThreadPool() 非核心线程池,用此方法创建的线程池只有非核心线程
  • Executors.newSingleThreadExecutor() 单线程池,用此方法创建的线程池只有一个核心线程
  • Executors.newScheduledThreadPool(5) 调度线程池,用此方法创建的线程池可设置核心线程,非核心线程为最大值

几种方式底层都是实现ThreadPoolExecutor构造参数

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 目录 一、线程池的优点 二、线程池创建中各个参数的含义 三、ThreadPoolExecutor的任务添加执行流程...
    mumuxi_阅读 2,204评论 0 1
  • 目录介绍 01.实际开发问题 02.线程池的优势 03.ThreadPoolExecutor参数 04.Threa...
    杨充211阅读 989评论 1 7
  • Android中线程池的概念源自Java中的Executor,Executor是一个接口,真正的实现类是Threa...
    笑对浮华阅读 1,822评论 0 3
  • 线程 线程在Android中是个很重要的概念,从用途来说,线程分为主线程与子线程,主线程用于处理界面相关事情,子线...
    我好芒阅读 29,090评论 0 34
  • 引言 在Android开发中,只要是耗时的操作都需要开启一个线程来执行。例如网络访问必须放到子线程中执行,否则会抛...
    落叶的位置丶阅读 747评论 0 1