Android开发中的线程池使用

news2024/11/18 15:38:21

一、前言

        既然Android中已经有了线程的概念,那么为什么需要使用线程池呢?我们从两个方面给出使用线程池的原因。

        首先线程的新建和销毁都是存在性能上的消耗的,如果一个时间段有大量的网络请求,那么就需要多个线程的创建与销毁,性能上的损耗可想而知。

        其次多个线程的存在也会占用CPU的执行时间段。我们知道如果只有一个CPU存在,那么线程的执行都是CPU轮流将执行时间分配给每一个线程。如果同时有多个子线程存在,那么相应的分配到主线程的CPU执行时间也会变少,这样App很大可能会出现卡顿现象。
鉴于上述两方面的原因,我们引进来了线程池这样一个概念,线程的创建、调度、销毁等都是由线程池来管理,这样就可以做到线程的重用,不必每次都新建一个线程,减少了线程创建和销毁的性能损耗。同时线程池会限制创建线程的个数,让App中的线程个数保持在一个可控的范围,这样也可以控制多个线程抢占主线程的资源。


 

二、线程池的优点

1.重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
2.能有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象。
3.能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。

三、ThreadPoolExecutor

        Android中的线程池的概念来源于java中的Executor,  Executor是一个接口,真正的线程池的实现为ThreadPoolExecutor.  ThreadPoolExecutor提供了一系列参数来配置线程池,通过不同的参数可以创建不同类型的线程池.

        ThreadPoolExecutor是线程池的真正实现,它的构造方法提供一系列参数来配置线程池.

我们来看看它的构造方法

源码路径: libcore/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java

  // Public constructors and methods

    /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters and default thread factory and rejected execution handler.
     * It may be more convenient to use one of the {@link Executors} factory
     * methods instead of this general purpose constructor.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue} is null
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

对应的参数说明:

四、线程池分类

定义的源码路径为: /libcore/ojluni/src/main/java/java/util/concurrent/Executors.java

根据参数的不同配置,Java内置了4种常用线程池:

  • 定长线程池(FixedThreadPool) 调用Executors.newFixedThreadPool()创建
  • 定时线程池(ScheduledThreadPool )调用Executors.newScheduledThreadPool()创建
  • 缓存线程池(CachedThreadPool)调用Executors.newCachedThreadPool()创建
  • 单例线程池(SingleThreadExecutor)调用Executors.newSingleThreadExecutor()创建

 特点和对比图

总结的思维导图:

五、使用方法

// 1. 创建线程池
   // 创建时,通过配置线程池的参数,从而实现自己所需的线程池
   Executor threadPool = new ThreadPoolExecutor(
                                              CORE_POOL_SIZE,
                                              MAXIMUM_POOL_SIZE,
                                              KEEP_ALIVE,
                                              TimeUnit.SECONDS,
                                              sPoolWorkQueue,
                                              sThreadFactory
                                              );
    // 注:在Java中,已内置4种常见线程池

// 2. 向线程池提交任务:execute()
    // 说明:传入 Runnable对象
       threadPool.execute(new Runnable() {
            @Override
            public void run() {
                ... // 线程执行任务
            }
        });

// 3. 关闭线程池shutdown() 
  threadPool.shutdown();
  
  // 关闭线程的原理
  // a. 遍历线程池中的所有工作线程
  // b. 逐个调用线程的interrupt()中断线程(注:无法响应中断的任务可能永远无法终止)

  // 也可调用shutdownNow()关闭线程:threadPool.shutdownNow()
  // 二者区别:
  // shutdown:设置 线程池的状态 为 SHUTDOWN,然后中断所有没有正在执行任务的线程
  // shutdownNow:设置 线程池的状态 为 STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表
  // 使用建议:一般调用shutdown()关闭线程池;若任务不一定要执行完,则调用shutdownNow()

六、Demo

我们通过源码来看下是怎么使用的:

源码片段:

/Dialer/java/com/android/voicemail/impl/transcribe/TranscriptionService.java

1. 创建一个单例线程池

  private ExecutorService getExecutorService() {
    if (executorService == null) {
      // The common use case is transcribing a single voicemail so just use a single thread executor
      // The reason we're not using DialerExecutor here is because the transcription task can be
      // very long running (ie. multiple minutes).
      executorService = Executors.newSingleThreadExecutor();
    }
    return executorService;
  }

2. 调用 execute(Runnable  runnable)方法,执行任务

      activeTask =
          configProvider.shouldUseSyncApi()
              ? new TranscriptionTaskSync(
                  this, new Callback(), workItem, getClientFactory(), configProvider)
              : new TranscriptionTaskAsync(
                  this, new Callback(), workItem, getClientFactory(), configProvider);
    //执行任务
    getExecutorService().execute(activeTask);

3. 任务执行完毕后,调用shutdown方法

@Override
  @MainThread
  public void onDestroy() {
    if (executorService != null) {
      executorService.shutdownNow();
      executorService = null;
    }
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/112894.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NSGA and NSGA-II

目录1 NSGA1.1 传统多目标优化方法1.2 多目标转为单目标的缺点1.3 权重向量距离说明1.4 NSGA方法1.4.1 流程1.4.2 关键步骤1.5 注意2 NSGA-II2.1 NSGA的缺点2.2 NSGA-II在NSGA上的变动2.3 NSGA-II流程1 NSGA 1.1 传统多目标优化方法 使用权重向量&#xff0c;将多目标问题转化…

Java入门练习题及其答案第一弹

Java入门练习题及其答案第一弹 文章目录Java入门练习题及其答案第一弹素数打印乘法口诀表最大公约数水仙花数二进制中1的个数二进制奇偶数位素数打印 只能被1和自己整除 import java.util.Scanner;public static void main(String[] args) {Scanner scanner new Scanner(Sys…

UI自动化测试-第一个测试脚本

前提 我们在进行UI自动化测试时&#xff0c;一般采用javaselenium或者pythonselenium的方式。由于python比较简单&#xff0c;上手快&#xff0c;因此建议大家采用pythonselenium的方式来进行UI自动化。 1、安装pycharm PyCharm是一种Python IDE&#xff08;Integrated Deve…

【OpenCV-Python】教程:7-5 理解SVM

OpenCV Python SVM 学习 【目标】 直观理解 SVM 【理论】 线性可分 下图有两种类型的数据&#xff0c;红色和蓝色。在kNN中&#xff0c;对于一个测试数据&#xff0c;我们用来测量它与所有训练样本的距离&#xff0c;并取距离最小的一个。测量所有的距离需要大量的时间&am…

计算距离春节还有多长时间

你知道距离春节&#xff0c;还剩下多少时间吗&#xff1f; 或许你已经在默默心算了。 可是&#xff0c;如果我想要精确一点的结果&#xff0c;比如精确到多少分钟、多少秒呢&#xff1f; 要怎么计算呢&#xff1f; 这里可以使用Python进行计算。 首先&#xff0c;需要导入…

Opencv项目实战:18 人体姿态检测

目录 0、项目介绍 1、效果展示 2、项目搭建 3、项目代码讲解与介绍 Basics.py PoseModule.py Example.py 人体姿态图​编辑 4、项目资源 5、项目总结 0、项目介绍 mediapipe中有人体姿态检测的功能&#xff0c;今天我们就将实现最最基础的人体姿态估计项目&#xff0c;它…

【C++】深拷贝和浅拷贝

目录 浅拷贝 深拷贝 字符串的构造 例有两个类的深拷贝&#xff1a; 浅拷贝 在类中&#xff0c;若我们不写拷贝构造函数&#xff0c;则程序会提供一个默认的拷贝构造函数&#xff0c;该函数为浅拷贝。 //默认拷贝构造 ---浅拷贝--值复制 类名(const 类名& 形参名) {成…

【实时数仓】DWS层之商品主题计算、地区主题表(FlinkSQL)

文章目录一 DWS层-商品主题计算1 把JSON字符串数据流转换为统一数据对象的数据流&#xff08;1&#xff09;转换订单宽表流数据&#xff08;2&#xff09;转换支付宽表流数据2 把统一的数据结构流合并为一个流&#xff08;1&#xff09;代码&#xff08;2&#xff09;测试3 设定…

216. 组合总和 III

216. 组合总和 III 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 示例 1: 输入: k 3, n 7 输…

3.2 Static Terrestrial Laser Scanners 静态地基激光扫描仪

本章节介绍的静态地基激光扫描系统指的是那些在一个固定位置的位置上对周边场景地物特征进行扫描的设备。该类型设备的扫描测量机制是&#xff0c;通过激光测距仪进行斜距测量&#xff0c;与此同时通过水平和竖直两个方向上同步运动的角度编码器来记录角度变化值&#xff08;如…

编译原理——正规式、NFA构造DFA

一、DFA和NFA的区别 NFA&#xff1a;非确定有限自动机 DFA&#xff1a;确定有限自动机 NFA在同一状态&#xff0c;可以有多条出边&#xff0c;DFA在同一状态&#xff0c;只能有一条出边&#xff1b; NFA的初态可以具有多个&#xff0c;DFA的初态是唯一的&#xff1b; 比如这个…

数据结构入门——栈和队列详解

栈和队列详解1 栈1.1 栈的概念及结构1.2 栈的实现1.3 支持动态增长的栈1.3.1 结构声明1.3.2 栈的初始化和销毁1.3.3 入栈和出栈操作1.3.4 栈的判空和元素个数2 队列2.1 队列的概念及结构2.2 队列的实现2.3 链表实现队列2.3.1 结构声明2.3.2 队列的初始化和销毁2.3.3 队列入队和…

【工作流Activiti7】4、Activiti7 结束/终止流程

1. 结束/终止 正在运行的流程实例 思路&#xff1a;跟回退一样的思路一样&#xff0c;直接从当前节点跳到结束节点&#xff08;EndEvent&#xff09; /*** 结束任务* param taskId 当前任务ID*/ public void endTask(String taskId) {// 当前任务Task task taskService…

Tomcat学习

文章目录1、Tomcat是什么&#xff1f;2、Tomcat安装部署java环境部署tomcat目录结构介绍webapps目录bin目录tomcat启停方式3、Tomcat配置文件tomcat-users.xmlserver.xml结构组件详情配置文件注释4、Tomcat端口5、JVM调优6、Tomcat启动慢解决7、Tomcat面试题目1.Tomcat的默认端…

npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称

一、问题描述 首次用vscode运行vue项目时&#xff0c;报错&#xff1a; npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 二、解决 我的解决过程&#xff1a;检查是否安装node.js环境 已安装node 这样一来&#xff0c;真不知道怎么回事了。环境也没有…

五、Arduino IDE开发esp8266环境搭建

1、安装驱动程序 (1)安装USB转串口驱动程序。 (2)根据板载的USB转串口驱动芯片选择合适驱动安装。USB转串口芯片负责和电脑之间进行数据通信。 (3)常见USB转串口驱动 CP210x驱动:CP210x USB 至 UART 桥 VCP 驱动器 - 芯科科技 CH340驱动 2、Arduino IDE环境搭建 要想使用Ar…

数据结构与算法java实战篇--高级排序

目录 一.希尔排序 二.划分 三.快速排序 1. 快速排序的算法 2.选择枢纽 一.希尔排序 希尔排序是基于插入排序的算法来实现的&#xff0c;不同的是希尔排序是采用n-增量来实现排序&#xff0c;如下是希尔排序的图解&#xff1a; 希尔排序会先以n个增量对元素进行划分&#xf…

原神私服 grasscutter搭建及食用教程 v3.3

本教程搭建过程食用vmware虚拟机服务端搭建过程及其简单。照着教程操作即可。本次对应的版本是3.3的版本&#xff0c;后期会持续更新。 一.资源下载准备&#xff1a; 1.vmwera16虚拟机下载安装自己百度吧&#xff0c;非常简单。一路next安装完后再输入一个百度来的秘钥即可。…

【kafka】学习笔记(二)

学习笔记五、Kafka Broker5.1、在zookeeper的服务端存储的Kafka相关信息5.2、Kafka Broker 总体工作流程5.3、Kafka Broker 节点服役和退役5.3.1、节点服役5.3.2、节点退役5.4、Kafka Broker 副本5.4.1、副本信息5.4.3、Leader 选举流程5.4.3、 Leader 和 Follower 故障处理细节…

【OpenCV-Python】教程:7-6 SVM识别手写字符

OpenCV Python SVM 识别手写字符 【目标】 用 SVM 识别手写字符 【代码】 在kNN中&#xff0c;直接用的是像素亮度值&#xff0c;这次&#xff0c;我们将使用 Histogram of Oriented Gradients (HOG) 作为特征向量 import cv2 import numpy as npSZ 20 bin_n 16 # Numbe…