当前位置: 移动技术网 > IT编程>移动开发>Android > 浅谈Android 的线程和线程池的使用

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

玛丽外宿中歌曲,翻译行业,铁道警官高等专科学校分数线

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);

  }

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网