浅谈Android 的线程和线程池的使用

Android 的线程和线程池

从用途上分,线程分为主线程和子线程;主线程主要处理和界面相关的事情,子线程则往往用于耗时操作。

主线程和子线程

主线程是指进程所拥有的线程。Android 中主线程交 UI 线程,主要作用是运行四大组件以及处理它们和用户的交互;子线程的作业则是执行耗时任务。

Android 中的线程形态

1、AsyncTask AsyncTask 是一种轻量级的异步任务类,可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新 UI, AsyncTask 是一个抽象的泛型类,提供了 Params(参数的类型)、Progress(后台任务执行进度的类型) 和 Result(后台任务的返回结果的类型) 这三个泛型参数, AsyncTask 提供了4个核心方法

  • onPreExcute(),在主线程中执行,在异步任务执行之前,此方法会被调用,一般可以用于做一些准备工作。
  • doInBackground(Params...params),在线程池中执行,此方法用于执行异步任务,params 参数表示异步任务的输入参数。在此方法中可以通过 publishProgress 方法来更新任务的进度,publishProgress 方法会调用 onProgressUpdate 方法,另外此方法需要返回计算结果给 onPostExecute 方法。
  • onProgressUpdate(Progress...values),在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用。
  • onPostExecute(Resukt result),在主线程中执行,在异步任务执行之后,此方法会被调用,其中 result 参数是后台任务的返回值,即 doInBackground 的返回值。

onPreExcute 先执行,接着是 doInBackground,最后才是 onPostExecute。 当异步任务被取消时,onCancelled() 方法会被调用,这个时候 onPostExecute 则不会被调用。

2、AsyncTask 在具体的使用过程中的一些限制条件

  • AsyncTask 的类必须在主线程中加载;
  • AsyncTask 的对象必须在 UI 线程中创建;
  • 不要在程序中直接调用 onPreExecute、onPostExecute、doInBackground 和 onProgressUpdate 方法。
  • 一个 AsyncTask 对象只能执行一次,即只能调用一次 execute 方法,否则会报运行时异常。
  • 在 Android 1.6之前,AsyncTask 是串行执行任务的,Android 1.6的时候 AsyncTask 开始采用线程池处理并行任务,但是从 Android 3.0开始为了避免 AsyncTask 所带来的并发错误,AsyncTask 又采用一个线程来串行执行任务。但是在 Android 3.0 以及后续的版本中,仍然可以通过 AsyncTask 的 executeOnExecutor 方法来并行地执行任务。

3、AsyncTask 的工作原理 AsyncTask 中有两个线程池(SerialExecutor 和 THREAD_POOL_EXECUTOR) 和一个 Handler(InternalHandler),线程池 SerialExecutor 用于任务的排队,线程池 THREAD_POOL_EXECUTOR 用于真正地执行任务,InternalHandler 用于将执行环境从线程池切换到主线程。

4、HandlerThread HandlerThread 继承了 Thread,是一种可以使用 Handler 的 Thread, 它的实现就是在 run 方法中通过 Looper.prepare() 来创建消息队列,并通过 Looper.loop() 来开启消息循环。

与普通的 Thread 相比,普通 Thread 主要用于在 run 方法中执行一个耗时任务,而 HandlerThread 在内部创建了消息队列,外界需要通过 Handler 的消息方式来通知 HandlerThread 执行一个具体的任务。

由于 HandlerThread 的 run 方法是一个无限循环,因此当明确不需要在使用 HandlerThread 时,可以通过它的 quit 或者 quitSafely 方法来终止线程的执行。

5、IntentService IntentService 是一种特殊的 Service,继承了 Service 并且是一个抽象类,必须创建它的子类才能使用 IntentService。IntentService可用于执行后台耗时任务,任务执行后会自动停止,并且它的优先级比单纯的线程要高很多,不容易被系统杀死。在实现上,IntentService 封装了 HandlerThread 和 Handler。

Android 中的线程池

线程池的优点

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

ThreadPoolExecutor ThreadPoolExecutor 是线程的真正实现。

public ThreadPoolExecutor(int corePoolSize,
              int maximumPoolSize,
              long keepAliveTime,
              TimeUnit unit,
              BlockingQueue<Runnable> workQueue,
              ThreadFactory threadFactory)
  • corePoolSize 线程池的核心线程数,默认情况下,核心线程会在线程池中一直存活,及时处于闲置状态。
  • maximumPoolSize 线程池所能容纳的最大线程数,当活动线程数达到这个数值后,后续的新任务将会被阻塞。
  • keepAliveTime 非核心线程闲置时的超时时长,超过这个时长,非核心线程就会被回收。
  • unit 用于指定 keepAliveTime 参数的时间单位,这是一个枚举,常用的有 TimeUnit、MILLSECONDS(毫秒)、TimeUnit.SECONDS(秒) 以及 TimeUnit.MINUTES(分钟)。
  • workQueue 线程池中的任务队列,通过线程池的 execute 方法提交的 Runnable 对象会存储在这个参数中。
  • threadFactory 线程工厂,为线程池通过创建新线程的功能。ThreadFactory 是一个接口,只有 一个方法:Thread newThread(Runnable r)。

ThreadPoolExecutor 执行任务时遵循的规则

  • 如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务;
  • 如果线程池中的线程数量已经达到或者超过核心线程的数量,那么任务会被插入到任务队列中排队等待执行;
  • 如果在步骤2中无法将任务插入到任务队列中,这往往是由于任务队列已满,这个时候如果线程数量为达到线程池规定的最大值,那么会立刻启动一个非核心线程来执行任务。
  • 如果步骤3中线程数量已经达到线程池规定的最大值,那么就拒绝执行此任务, ThreadPoolExecutor 会调用 RejectedExecutionHandler 的 rejectedExecution 方法来通知调用者。

线程池的分类

  • FixedThreadPool 通过 Executors 的 newFixedThreadPool 方法来创建。是一种线程数量固定的线程池,当线程处于空闲状态时并不会被回收,除非线程池被关闭。FixedThreadPool 中只有核心线程并且这些核心线程没有超时机制,另外任务队列也是没有大小限制。
  • CachedThreadPool 通过 Executors 的 newCachedThreadPool 方法来创建。是一种线程数量不定的线程池,只有非核心线程,最大线程数为 Integer.MAX_VALUE。线程池中的空闲线程都有超时机制,这个超时时长为60秒,超过60秒闲置线程就会被回收。CachedThreadPool 的任务队列相当于一个空集合,这样会导致任何任务都会被立即执行。
  • ScheduledThreadPool 通过 Executors 的 newScheduledThreadPool 方法来创建。它的核心线程数量是固定的,而非核心线程数是没有限制的,并且当非核心线程闲置时会被立即回收。ScheduledThreadPool 这类线程池主要用于执行定时任务和具有固定周期的重复任务。
  • SingleThreadExecutor 通过 Executors 的 newSingleThreadExecutor 方法来创建。这类线程池内部只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。SingleThreadExecutor 的意义在于统一所有的外界任务到一个线程中,这使得在这些任务之间不需要处理线程同步的问题。

系统预置4种线程池的典型使用方法:

Runnable command = new Runnable(){
    @Override
    public void run(){
      SystemClock.sleep(2000);
    }

  ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
  fixedThreadPool.execute(command);

  ExecutorService cachedThreadPool =Executors.newCachedThreadPool();
  cachedThreadPool.execute(command);

  ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
  // 2000ms 后执行 command
  scheduledThreadPool.schedule(command,2000,TimeUnit.MILLISECONDS);
  // 延迟10ms,每个1000ms执行一次 command
  scheduledThreadPool.scheduleAtFixedRate(command,10,1000,TimeUnit.MILLISECONDS);

  ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
  singleThreadExecutor.execute(command);

  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android开发实现各种图形绘制功能示例

    本文实例讲述了Android开发实现各种图形绘制功能.分享给大家供大家参考,具体如下: 这里结合本人的开发事例,简单介绍一下如何在Android平台下实现各种图形的绘制. 首先自定义一个View类,这个view类里面需要一个Paint对象来控制图形的属性,需要一个Path对象来记录图形绘制的路径,需要一个Canvas类来执行绘图操作,还需要一个Bitmap类来盛放绘画的结果. Paint mPaint = new Paint(); mPaint.setAntiAlias(true); mPain

  • Android 中WallpaperManager用法实例

    Android 中WallpaperManager用法实例 注意:壁纸的设置得加入权限: <uses-permission android:name="android.permission.SET_WALLPAPER"/> 1.WallpaperManager  对象的获得: wallpaperManager =WallpaperManager.getInstance(this); 2.设置壁纸的方法: 方法一:wallpaperManager.setBitmap(); /

  • Android编程实现播放视频时切换全屏并隐藏状态栏的方法

    本文实例讲述了Android编程实现播放视频时切换全屏并隐藏状态栏的方法.分享给大家供大家参考,具体如下: 1. Demo示例: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (this.getResources().getConfiguration().ori

  • 详解Android 中AsyncTask 的使用

    详解Android 中AsyncTask 的使用 1.首先我们来看看AsyncTask 的介绍:   Handler 和 AsyncTask 都是android 中用来实现异步任务处理的方式:其中: Handler 实例向 UI 线程发送消息,完成界面更新, 优点:对整个过程控制的比较精细:         缺点:代码相对臃肿,多个任务同时执行时,不易对线程进行精确的控制: AsyncTask :比Handler 更轻量级一些,适用于简单的异步处理: 优点:简单 | 快捷 | 过程可控:    

  • Android使用GridView实现日历的方法

    在开发中可能会遇到某些情况下需要用到日历的功能,并且还要在日历上加标签什么的,最重要的就是android自带的日历由于各个系统版本不同导致日历的样式也不同,这样就会导致使用起来比较麻烦..而且在日历中加标签也不好实现...所以很多时候日历都是自己去实现的...由于自定义日历会比较麻烦...这里就教大家使用GridView来实现,主要是我们比较熟悉这个控件...到时候也可以根据自己的情况进行封装为自定义View 下面就先看看效果图.由于是从项目中抽取出来的,某些地方定制性比较强, 可以根据需求自行

  • Android开发之全屏与非全屏的切换设置方法小结

    本文实例讲述了Android开发之全屏与非全屏的切换设置方法.分享给大家供大家参考,具体如下: 静态方法 1. 代码方式 在Activity类OnCreate方法中设置,代码如下 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().se

  • Android Spinner 组件的应用实例

    Android Spinner 组件 Spinner: 下拉组件 使用事项:布局在XML 中实现,具体的数据在JAVA 代码中实现: 所用知识点: 数组适配器:ArrayAdapter  用于关系M 层和 C 层: 事件:OnItemSelectedListener; 案列:查看十二星座效果图: xml:代码如下: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tool

  • 浅谈Android中使用异步线程更新UI视图的几种方法

    在Android中子线程是不能更新ui的. 所以我们要通过其他方式来动态改变ui视图, 1.runOnUiThread activity提供的一个轻量级更新ui的方法,在Fragment需要使用的时候要用getActivity.runOnUiThread开启线程 这种方法最简单,方便更新一些不需要判断的通知,比如在聊天项目中动态获取未读消息数量. runOnUiThread(new Runnable() { @Override public void run() { sendMessage("[

  • 浅谈Timer和TimerTask与线程的关系

    1. Timer是一个定时器,它可以根据指定的时间,指定的执行周期来执行固定的任务TimerTask,例子如下: Timer与线程的关系,在Timer源代码中可现如下代码: 1. 以下为Timer的默认构造方法,起调用了自身的一个有参构造函数: 2.有参构造函数代码如下: 3. 有参构造函数设置了当前线程的名字并启动该线程,线程代码如下: 4. TimerThread类的源代码如下: 由以上代码可以看出Timer其实就是一个Thread类的子类. TimerTask与线程的关系: 1. 以下为T

  • 浅谈Android中AsyncTask的工作原理

    概述 实际上,AsyncTask内部是封装了Thread和Handler.虽然AsyncTask很方便的执行后台任务,以及在主线程上更新UI,但是,AsyncTask并不合适进行特别耗时的后台操作,对于特别耗时的任务,个人还是建议使用线程池.好了,话不多说了,我们先看看AsyncTask的简单用法吧. AsyncTask使用方法 AsyncTask是一个抽象的泛型类.简单的介绍一下它的使用方式代码如下: package com.example.huangjialin.myapplication;

  • 浅谈Android IPC机制之Binder的工作机制

    进程和线程的关系 按照操作系统中的描述,线程是CPU调度的最小单位,同时线程也是一种有限的系统资源.而进程一般是指一个执行单元,在pc端或者移动端上是指一个程序或者一个应用.一个进程中可以包含一个或者是多个线程.所以他们的关系应该是包含和被包含的关系. 跨进程的种类 在Android中跨进程通信的方式有很多种,Bundle,文件共享,AIDL,Messenger,ContentProvider,Socket,这些都能实现进程间之间的通信,当然,虽然都能够实现进程间通信,但是他们之间的实现原理或者

  • 浅谈Android中Service的注册方式及使用

    Service通常总是称之为"后台服务",其中"后台"一词是相对于前台而言的,具体是指其本身的运行并不依赖于用户可视的UI界面,因此,从实际业务需求上来理解,Service的适用场景应该具备以下条件: 1.并不依赖于用户可视的UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的): 2.具有较长时间的运行特性. 1.Service AndroidManifest.xml 声明 一般而言,从Service的启动方式上

  • 浅谈django url请求与数据库连接池的共享问题

    但凡介绍数据库连接池的文章,都会说"数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正是针对这个问题提出来的.数据库连接池负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个:释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏.这项技术能明显提高对数据库操作的性能." 这句

  • 浅谈C#中的string驻留池

    昨天看群里在讨论C#中的string驻留池,炒的火热,几轮下来理论一堆堆,但是在证据提供上都比较尴尬.虽然这东西很基础,但比较好的回答也不是那么容易,这篇我就以我能力范围之内跟大家分享一下 一:无处不在的池 开发这么多年,相信大家对'池' 这个概念都耳熟能详了,连接池,线程池,对象池,还有这里的驻留池,池的存在就是为了复用为了共享,独乐乐不如众乐乐,毕竟一个字符串的生成和销毁既浪费空间又浪费时间,还不如先养着. 1. 说说现象 通常我们臆想中是这么认为的,定义几个字符串变量,堆上就会分配几个st

  • 浅谈Android Studio 4.1 更新内容

    概览 Android Studio 4.1 目前已经发布,该版本共修复了2370 个 bug 以及 275 个 issue,主要包含如下新增功能: 设计 Material Design 组件库的更新 开发 Database Inspector 功能 直接在 Android Studio 中运行模拟器 Dagger 导航支持 使用 TensorFlow Lite 模型 构建与测试 Android 模拟器支持折叠屏 Apply Changes 更新 从 AAR 中导出 C/C++ 中的依赖 Nati

  • 浅谈Android手机的抢红包插件

    前语 最近,Android手机上的手机管家更新了新版本,提供了红包闹钟功能,只要有微信红包或者QQ红包,就会自动提醒.恰逢最近又在做UI自动化的工作,使用到UI Automator框架.几行代码,就可以让手机自动完成某些操作,很有意思,今天就来扒一扒这背后的原理. UI Automator 传统的手工测试,我们需要点击一些控件元素,来查看输出的结果是否符合预期.比如在登录界面,输入正确的用户名和密码,点击登录按钮后,就可以正常登录. 如果这些操作,每一次都需要手工执行的话,是需要大量的人力成本的

  • 浅谈Android性能优化之内存优化

    1.Android内存管理机制 1.1 Java内存分配模型 先上一张JVM将内存划分区域的图 程序计数器:存储当前线程执行目标方法执行到第几行. 栈内存:Java栈中存放的是一个个栈帧,每个栈帧对应一个被调用的方法.栈帧包括局部标量表, 操作数栈. 本地方法栈:本地方法栈主要是为执行本地方法服务的.而Java栈是为执行Java方法服务的. 方法区:该区域被线程共享.主要存储每个类的信息(类名,方法信息,字段信息等).静态变量,常量,以及编译器编译后的代码等. 堆:Java中的堆是被线程共享的,

随机推荐