美文网首页
Android线程池

Android线程池

作者: 人世看客 | 来源:发表于2022-05-18 18:09 被阅读0次

    一、为什么要用线程池

    目前就我在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构造参数

    相关文章

      网友评论

          本文标题:Android线程池

          本文链接:https://www.haomeiwen.com/subject/risaurtx.html