一、简介

  • 不同应用在各自独立的进程中运行。当应用以任何形式启动时,系统为其创建进程,该进程将持续运行。当进程完成当前任务处于等待状态,且系统资源不足时,系统自动回收。
  • 在启动应用时,系统会为该应用创建一个称为“主线程”的执行线程。该线程随着应用创建或消失,是应用的核心线程。
  • UI 界面的显示和更新等操作,都是在主线程上进行。主线程又称 UI 线程,默认情况下,所有的操作都是在主线程上执行。如果需要执行比较耗时的任务(如下载文件、查询数据库),可创建其他线程来处理。
  • 如果应用的业务逻辑比较复杂,可能需要创建多个线程来执行多个任务,这种情况下,代码复杂难以维护,任务与线程的交互也会更加繁杂。要解决此问题,可以使用“TaskDispatcher”来分发不同的任务。

二、API 说明

  • TaskDispatcher 是一个任务分发器,它是 Ability 分发任务的基本接口,隐藏任务所在线程的实现细节。
  • 为保证应用有更好的响应性,需要设计任务的优先级。在 UI 线程上运行的任务默认以高优先级运行,如果某个任务无需等待结果,则可以用低优先级。
  • 线程优先级说明:
优先级 详细描述
HIGH 最高任务优先级,比默认优先级、低优先级的任务有更高的几率得到执行
DEFAULT 默认任务优先级, 比低优先级的任务有更高的几率得到执行
LOW 低任务优先级,比高优先级、默认优先级的任务有更低的几率得到执行
  • TaskDispatcher 具有多种实现,每种实现对应不同的任务分发器。在分发任务时可以指定任务的优先级,由同一个任务分发器分发出的任务具有相同的优先级。
  • 系统提供的任务分发器有 GlobalTaskDispatcher、ParallelTaskDispatcher、SerialTaskDispatcher 、SpecTaskDispatcher。
  • GlobalTaskDispatcher:全局并发任务分发器,由 Ability 执行 getGlobalTaskDispatcher() 获取,适用于任务之间没有联系的情况。一个应用只有一个 GlobalTaskDispatcher,它在程序结束时才被销毁。
 TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);
  • ParallelTaskDispatcher:并发任务分发器,由 Ability 执行 createParallelTaskDispatcher() 创建并返回。与 GlobalTaskDispatcher 不同的是,ParallelTaskDispatcher 不具有全局唯一性,可以创建多个,在创建或销毁 dispatcher 时,需要持有对应的对象引用。
 String dispatcherName = "parallelTaskDispatcher";TaskDispatcher parallelTaskDispatcher = createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);
  • SerialTaskDispatcher:串行任务分发器,由 Ability 执行 createSerialTaskDispatcher() 创建并返回。由该分发器分发的所有的任务都是按顺序执行,但是执行这些任务的线程并不是固定的。
    • 如果要执行并行任务,应使用 ParallelTaskDispatcher 或者 GlobalTaskDispatcher,而不是创建多个 SerialTaskDispatcher。
    • 如果任务之间没有依赖,应使用 GlobalTaskDispatcher 来实现。它的创建和销毁由开发者自己管理,在使用期间需要持有该对象引用。
 String dispatcherName = "serialTaskDispatcher";TaskDispatcher serialTaskDispatcher = createSerialTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);
  • SpecTaskDispatcher:专有任务分发器,绑定到专有线程上的任务分发器。目前已有的专有线程为UI线程,通过 UITaskDispatcher 进行任务分发。
  • UITaskDispatcher:绑定到应用主线程的专有任务分发器, 由 Ability 执行 getUITaskDispatcher() 创建并返回。 由该分发器分发的所有的任务都是在主线程上按顺序执行,它在应用程序结束时被销毁。
 TaskDispatcher uiTaskDispatcher = getUITaskDispatcher();

三、线程开发流程

① syncDispatch
  • 同步派发任务:派发任务并在当前线程等待任务执行完成。在返回前,当前线程会被阻塞。
  • 如下代码示例,展示了如何使用 GlobalTaskDispatcher 派发同步任务:
 TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);globalTaskDispatcher.syncDispatch(new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "sync task1 run");}});HiLog.info(LABEL_LOG, "after sync task1");globalTaskDispatcher.syncDispatch(new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "sync task2 run");}});HiLog.info(LABEL_LOG, "after sync task2");globalTaskDispatcher.syncDispatch(new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "sync task3 run");}});HiLog.info(LABEL_LOG, "after sync task3");// 执行结果如下:// sync task1 run// after sync task1// sync task2 run// after sync task2// sync task3 run// after sync task3
  • 如果对 syncDispatch 使用不当,将会导致死锁。如下情形可能导致死锁发生:
    • 在专有线程上,利用该专有任务分发器进行 syncDispatch。
    • 在被某个串行任务分发器(dispatcher_a)派发的任务中,再次利用同一个串行任务分发器(dispatcher_a)对象派发任务。
    • 在被某个串行任务分发器(dispatcher_a)派发的任务中,经过数次派发任务,最终又利用该(dispatcher_a)串行任务分发器派发任务。例如:dispatcher_a 派发的任务使用 dispatcher_b 进行任务的派发,在 dispatcher_b 派发的任务中又利用 dispatcher_a 进行派发任务。
    • 串行任务分发器(dispatcher_a)派发的任务中利用串行任务分发器(dispatcher_b)进行同步派发任务,同时 dispatcher_b 派发的任务中利用串行任务分发器(dispatcher_a)进行同步派发任务。在特定的线程执行顺序下将导致死锁。
② asyncDispatch
  • 异步派发任务:派发任务,并立即返回,返回值是一个可用于取消任务的接口。
  • 如下代码示例,展示了如何使用 GlobalTaskDispatcher 派发异步任务:
 TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);Revocable revocable = globalTaskDispatcher.asyncDispatch(new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "async task1 run");}});HiLog.info(LABEL_LOG, "after async task1");// 执行结果可能如下:// after async task1// async task1 run
③ delayDispatch
  • 异步延迟派发任务:异步执行,函数立即返回,内部会在延时指定时间后将任务派发到相应队列中。延时时间参数仅代表在这段时间以后任务分发器会将任务加入到队列中,任务的实际执行时间可能晚于这个时间。具体比这个数值晚多久,取决于队列及内部线程池的繁忙情况。
  • 如下代码示例,展示了如何使用 GlobalTaskDispatcher 延迟派发任务:
 final long callTime = System.currentTimeMillis();final long delayTime = 50L;TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT); Revocable revocable = globalTaskDispatcher.delayDispatch(new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "delayDispatch task1 run");final long actualDelay = System.currentTimeMillis() - callTime;HiLog.info(LABEL_LOG, "actualDelayTime >= delayTime: %{public}b", (actualDelay >= delayTime));}}, delayTime);HiLog.info(LABEL_LOG, "after delayDispatch task1");// 执行结果可能如下:// after delayDispatch task1// delayDispatch task1 run// actualDelayTime >= delayTime : true
④ Group
  • 任务组:表示一组任务,且该组任务之间有一定的联系,由 TaskDispatcher 执行 createDispatchGroup 创建并返回。将任务加入任务组,返回一个用于取消任务的接口。
  • 如下代码示例展示了任务组的使用方式:将一系列相关联的下载任务放入一个任务组,执行完下载任务后关闭应用。
 String dispatcherName = "parallelTaskDispatcher";TaskDispatcher dispatcher = createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);// 创建任务组。Group group = dispatcher.createDispatchGroup();// 将任务1加入任务组,返回一个用于取消任务的接口。dispatcher.asyncGroupDispatch(group, new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "download task1 is running");}});// 将与任务1相关联的任务2加入任务组。dispatcher.asyncGroupDispatch(group, new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "download task2 is running");}});// 在任务组中的所有任务执行完成后执行指定任务。dispatcher.groupDispatchNotify(group, new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "the close task is running after all tasks in the group are completed");}});​// 可能的执行结果:// download task1 is running// download task2 is running// the close task is running after all tasks in the group are completed// 另外一种可能的执行结果:// download task2 is running// download task1 is running// the close task is running after all tasks in the group are completed
⑤ Revocable
  • 取消任务:Revocable 是取消一个异步任务的接口。异步任务包括通过 asyncDispatch、delayDispatch、asyncGroupDispatch 派发的任务。如果任务已经在执行中或执行完成,则会返回取消失败。
  • 如下代码示例展示了如何取消一个异步延时任务:
 TaskDispatcher dispatcher = getUITaskDispatcher();Revocable revocable = dispatcher.delayDispatch(new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "delay dispatch");}}, 10);boolean revoked = revocable.revoke();HiLog.info(LABEL_LOG, "%{public}b", revoked);​// 一种可能的结果如下 :// true
⑥ syncDispatchBarrier
  • 同步设置屏障任务:在任务组上设立任务执行屏障,同步等待任务组中的所有任务执行完成,再执行指定任务。
  • 在全局并发任务分发器(GlobalTaskDispatcher)上同步设置任务屏障,将不会起到屏障作用。
  • 如下代码示例展示了如何同步设置屏障:
 String dispatcherName = "parallelTaskDispatcher";TaskDispatcher dispatcher = createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);// 创建任务组。Group group = dispatcher.createDispatchGroup();// 将任务加入任务组,返回一个用于取消任务的接口。dispatcher.asyncGroupDispatch(group, new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "task1 is running");  // 1}});dispatcher.asyncGroupDispatch(group, new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "task2 is running");  // 2}});dispatcher.syncDispatchBarrier(new Runnable() {@Overridepublic void run() {  HiLog.info(LABEL_LOG, "barrier");  // 3}});  HiLog.info(LABEL_LOG, "after syncDispatchBarrier");  // 4​// 1和2的执行顺序不定;3和4总是在1和2之后按顺序执行。// 可能的执行结果:// task1 is running// task2 is running// barrier// after syncDispatchBarrier// 另外一种执行结果:// task2 is running// task1 is running// barrier// after syncDispatchBarrier
⑦ asyncDispatchBarrier
  • 异步设置屏障任务:在任务组上设立任务执行屏障后直接返回,指定任务将在任务组中的所有任务执行完成后再执行。
  • 在全局并发任务分发器(GlobalTaskDispatcher)上异步设置任务屏障,将不会起到屏障作用。可以使用并发任务分发器(ParallelTaskDispatcher)分离不同的任务组,达到微观并行、宏观串行的行为。
  • 如下代码示例展示了如何异步设置屏障:
 TaskDispatcher dispatcher = createParallelTaskDispatcher("dispatcherName", TaskPriority.DEFAULT);// 创建任务组Group group = dispatcher.createDispatchGroup();// 将任务加入任务组,返回一个用于取消任务的接口dispatcher.asyncGroupDispatch(group, new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "task1 is running");  // 1}});dispatcher.asyncGroupDispatch(group, new Runnable() {@Overridepublic void run() {HiLog.info(LABEL_LOG, "task2 is running");  // 2}});dispatcher.asyncDispatchBarrier(new Runnable() {@Overridepublic void run() {  HiLog.info(LABEL_LOG, "barrier");  // 3}});  HiLog.info(LABEL_LOG, "after asyncDispatchBarrier");  // 4​// 1和2的执行顺序不定,但总在3之前执行;4不需要等待1、2、3执行完成// 可能的执行结果:// task1 is running// task2 is running// after asyncDispatchBarrier// barrier
⑧ applyDispatch
  • 执行多次任务:对指定任务执行多次。
  • 如下代码示例展示了如何执行多次任务:
 final int total = 10;final CountDownLatch latch = new CountDownLatch(total);final List<Long> indexList = new ArrayList<>(total);TaskDispatcher dispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT); // 执行任务 total 次。dispatcher.applyDispatch((index) -> {indexList.add(index);latch.countDown();}, total);// 设置任务超时。try {    latch.await();} catch (InterruptedException exception) {HiLog.error(LABEL_LOG, "latch exception");}HiLog.info(LABEL_LOG, "list size matches, %{public}b", (total == indexList.size()));// 执行结果:// list size matches, true

HarmonyOS之深入解析线程管理相关推荐

  1. HarmonyOS之深入解析线程间的通信

    一.概述 ① 基本概念 在开发过程中,开经常需要在当前线程中处理下载任务等较为耗时的操作,但是又不希望当前的线程受到阻塞.此时,就可以使用 EventHandler 机制. EventHandler ...

  2. c语言中的线程管理,深入解析C++编程中线程池的使用

    为什么需要线程池目前的大多数网络服务器,包括Web服务器.Email服务器以及数据库服务器等都具有一个共同点,就是单位时间内必须处理数目巨大的连接请求,但处理时间却相对较短. 传 统多线程方案中我们采 ...

  3. HarmonyOS学习路之开发篇——线程管理

    什么是线程管理 不同应用在各自独立的进程中运行.当应用以任何形式启动时,系统为其创建进程,该进程将持续运行.当进程完成当前任务处于等待状态,且系统资源不足时,系统自动回收. 在启动应用时,系统会为该应 ...

  4. [转]C++ 11 多线程--线程管理

    转载地址:https://www.cnblogs.com/wangguchangqing/p/6134635.html 说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并 ...

  5. C++ 11 多线程--线程管理

    说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...

  6. 《线程管理:线程基本操作》

    目录 线程管理 启动线程与(不)等待线程完成 特殊情况下的等待(使用trycath或rall) 后台运行线程 线程管理 启动线程与(不)等待线程完成 提供的函数对象被复制到新的线程的存储空间中,函数对 ...

  7. C++11多线程----线程管理

    说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...

  8. 二. 线程管理之线程池

    不忘初心 砥砺前行, Tomorrow Is Another Day ! 相关文章 一. 线程管理之Thread基础 二. 线程管理之线程池 三. 线程管理之ThreadLocal 四. 线程管理之A ...

  9. 《C++ Concurrencyin Action》第2章--线程管理

    前言 本章主要内容: 1 启动新线程 2 等待线程与分离线程 3 线程唯一标识符 好的!看来你已经决定使用多线程了.先做点什么呢?启动线程.结束线程,还是如何监管线程?在C++标准库中只需要管理std ...

最新文章

  1. C语言 之 PTA乙级错误集锦
  2. 慢SQL,压垮团队的最后一根稻草No.92
  3. 程序员的职业素养(读书笔记)-- 第一章
  4. python3 爬淘女郎
  5. Weblogic部署项目过程中的一些问题
  6. python sizeof函数_C++ sizeof 运算符 | 菜鸟教程
  7. python识别12306验证码_Python3.4实现的12306最新验证码识别
  8. LeetCode 226. 翻转二叉树(DFS BFS)
  9. 跨设备链路聚合_路由与交换技术(华为设备)第五讲---链路聚合
  10. qt如何在TetxEdit设置背景色(可以设置行或列)
  11. excel查看编码格式_Excel表格中格式转换的这些套路,你都get了吗?
  12. 天正电气html帮助,T20天正电气使用技巧
  13. 北京科技大学计算机复试面试,北京科技大学考研复试
  14. editplus的php插件,editplus的各式插件
  15. [zz] 基于sinc的音频重采样(一):原理
  16. 2023年全国最新工会考试精选真题及答案33
  17. 数据探查平台-元数据对标专利 -- 普帝
  18. 腾讯X5 浏览器内核加载
  19. Elasticsearch CCR源码分析
  20. J0ker的CISSP之路:复习-Information Security Management(2)

热门文章

  1. 一个回滚段收缩的实例
  2. i5 11300h和R5 5600H 参数对比哪个好
  3. 运维无小事,小事不运维
  4. List的remove(对象)操作有时候会报ConcurrentModificationException异常
  5. MYSQL基础笔记(三)-表操作基础
  6. SQL SERVER – Beginning of SQL Server Architecture – Terminology – Guest Post
  7. 使用asp.net中的跟踪功能
  8. HDOJ---1272 小希的迷宫[并查集]
  9. 什么能在main()函数之前或之后执行
  10. 疯狂python讲义pdf_火了!她说:“请给我推荐一本Python书!”