Android线程池使用及其原理

本文详细介绍了Android中线程池的使用及其原理,强调了线程池避免频繁线程创建销毁、统一管理的优势。文章通过分析ThreadPoolExecutor的构造参数,展示了FixedThreadPool、CachedThreadPool、SingleThreadPool、ScheduledThreadPool等常见线程池的特性和适用场景,以及如何自定义PriorityThreadPool。还探讨了Java中的阻塞队列和线程池的选择策略。
摘要由CSDN通过智能技术生成
一、为什么使用线程池

在android开发中经常会使用多线程异步来处理相关任务,而如果用传统的newThread来创建一个子线程进行处理,会造成一些严重的问题:

  • 在任务众多的情况下,系统要为每一个任务创建一个线程,而任务执行完毕后会销毁每一个线程,所以会造成线程频繁地创建与销毁。

  • 多个线程频繁地创建会占用大量的资源,并且在资源竞争的时候就容易出现问题,同时这么多的线程缺乏一个统一的管理,容易造成界面的卡顿。

  • 多个线程频繁地销毁,会频繁地调用GC机制,这会使性能降低,又非常耗时。

总而言之:频繁地为每一个任务创建一个线程,缺乏统一管理,降低性能,并且容易出现问题。

为了解决这些问题,就要用到今天的主角——线程池.

线程池使用的好处:

  • 对多个线程进行统一地管理,避免资源竞争中出现的问题。

  • (重点):对线程进行复用,线程在执行完任务后不会立刻销毁,而会等待另外的任务,这样就不会频繁地创建、销毁线程和调用GC。

  • JAVA提供了一套完整的ExecutorService线程池创建的api,可创建多种功能不一的线程池,使用起来很方便。

1. 内部原理逻辑

当线程池运行时,遵循以下工作逻辑:
在这里插入图片描述

二、几种常见的线程池
1、ThreadPoolExecutor 创建基本线程池

创建线程池,主要是利用ThreadPoolExecutor这个类,而这个类有几种构造方法,其中参数最多的一种构造方法如下:

   /*
    *@ ThreadPoolExecutor构造参数介绍
    */
    public ThreadPoolExecutor(
    //核心线程数,除非allowCoreThreadTimeOut被设置为true,否则它闲着也不会死
    int corePoolSize,
    //最大线程数,活动线程数量超过它,后续任务就会排队                   
    int maximumPoolSize,
    //超时时长,作用于非核心线程(allowCoreThreadTimeOut被设置为true时也会同时作用于核心线程),闲置超时便被回收           
    long keepAliveTime,                          
    //枚举类型,设置keepAliveTime的单位,有TimeUnit.MILLISECONDS(ms)、TimeUnit. SECONDS(s)等
    TimeUnit unit,
    //缓冲任务队列,线程池的execute方法会将Runnable对象存储起来
    BlockingQueue<Runnable> workQueue,
    //线程工厂接口,只有一个new Thread(Runnable r)方法,可为线程池创建新线程
    ThreadFactory threadFactory)
  • corePoolSize: 该线程池中核心线程的数量。

  • maximumPoolSize:该线程池中最大线程数量。(区别于corePoolSize)

  • keepAliveTime:从字面上就可以理解,是非核心线程空闲时要等待下一个任务到来的时间,当任务很多,每个任务执行时间很短的情况下调大该值有助于提高线程利用率。注意:当allowCoreThreadTimeOut属性设为true时,该属性也可用于核心线程。

  • unit:上面时间属性的单位

  • workQueue:任务队列,后面详述。

  • threadFactory:线程工厂,可用于设置线程名字等等,一般无须设置该参数。

ThreadPoolExecutor的各个参数所代表的特性注释中已经写的很清楚了,那么ThreadPoolExecutor执行任务时的心路历程是什么样的呢?(以下用currentSize表示线程池中当前线程数量)

  • 当currentSize<corePoolSize时,没什么好说的,直接启动一个核心线程并执行任务。

  • 当currentSize>=corePoolSize、并且workQueue未满时,添加进来的任务会被安排到workQueue中等待执行。

  • 当workQueue已满,但是currentSize<maximumPoolSize时,会立即开启一个非核心线程来执行任务。

  • 当currentSize>=corePoolSize、workQueue已满、并且currentSize>maximumPoolSize时,调用handler默认抛出RejectExecutionExpection异常。

在这里插入图片描述
设置好几个参数就可以创建一个基本的线程池,而之后的各种线程池都是在这种基本线程池的基础上延伸的。

下面贴个自己写的demo来熟悉具体的使用并且加深影响:

//创建基本线程池
final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,
        new LinkedBlockingQueue<Runnable>(100));

设置一个按钮mThreadPoolExecute,并在点击事件中使用线程池

 /**
  * 基本线程池使用
  */
 mThreadPoolExecute.setOnClickListener(new View.OnClickListener() {
   
            @Override
            public void onClick(View v) {
   

                for(int i = 0;i<30;i++){
   
                    final int finali = i;
                    Runnable runnable = new Runnable() {
   
                        @Override
                        public void run() {
   
                            try {
   
                                Thread.sleep(2000);
                                Log.d("Thread", "run: "+finali);
                                Log.d("当前线程:",Thread.currentThread().getName());
                            } catch (InterruptedException e) {
   
                                e.printStackTrace();
                            }
                        }
                    };
                    threadPoolExecutor.execute(runnable);
                }
            }
        });

结果会每2s打印三个日志。

具体过程:

  • execute一个线程之后,如果线程池中的线程数未达到核心线程数,则会立马启用一个核心线程去执行。

  • execute一个线程之后,如果线程池中的线程数已经达到核心线程数,且workQueue未满,则将新线程放入workQueue中等待执行。

  • execute一个线程之后,如果线程池中的线程数已经达到核心线程数但未超过非核心线程数,且workQueue已满,则开启一个非核心线程来执行任务。

  • execute一个线程之后,如果线程池中的线程数已经超过非核心线程数,则拒绝执行该任务,采取饱和策略,并抛出RejectedExecutionException异常。

demo中设置的任务队列长度为100,所以不会开启额外的5-3=2个非核心线程,如果将任务队列设为25,则前三个任务被核心线程执行,剩下的30-3=27个任务进入队列会满,此时会开启2个非核心线程来执行剩下的两个任务。

//新开启了thread-4与thread-5执行剩下的超出队列的两个任务28和29

2019-11-01 15:54:07.879 22284-22618/com.example.threadpooltest D/Thread:: 1
2019-11-01 15:
  • 10
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值