0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

鸿蒙系统中线程管理的使用

OpenHarmony技术社区 来源:鸿蒙技术社区 作者:开鸿HOS小鸿 2021-09-28 09:49 次阅读

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

在启动应用时,系统会为该应用创建一个称为“主线程”的执行线程。该线程随着应用创建或消失,是应用的核心线程。UI 界面的显示和更新等操作,都是在主线程上进行。

主线程又称 UI 线程,默认情况下,所有的操作都是在主线程上执行。如果需要执行比较耗时的任务(如下载文件、查询数据库),可创建其他线程来处理。

如果应用的业务逻辑比较复杂,可能需要创建多个线程来执行多个任务。这种情况下,代码复杂难以维护,任务与线程的交互也会更加繁杂。

要解决此问题,开发者可以使用 TaskDispatcher 来分发不同的任务。

TaskDispatcher 介绍

TaskDispatcher 是一个任务分发器,它是 Ability 分发任务的基本接口,隐藏任务所在线程的实现细节。

为保证应用有更好的响应性,我们需要设计任务的优先级。在 UI 线程上运行的任务默认以高优先级运行,如果某个任务无需等待结果,则可以用低优先级。

线程优先级介绍:

HIGH:最高任务优先级,比默认优先级、低优先级的任务有更高的几率得到执行。

DEFAULT:默认任务优先级, 比低优先级的任务有更高的几率得到执行。

LOW:低任务优先级,比高优先级、默认优先级的任务有更低的几率得到执行。

TaskDispatcher 具有多种实现,每种实现对应不同的任务分发器。在分发任务时可以指定任务的优先级,由同一个任务分发器分发出的任务具有相同的优先级。

系统提供的任务分发器有:

GlobalTaskDispatcher

ParallelTaskDispatcher

SerialTaskDispatcher

SpecTaskDispatcher

实践

①同步派发任务 syncDispatch

发任务并在当前线程等待任务执行完成。在返回前,当前线程会被阻塞:

/**

* 同步派发任务

*/

private void syncDispatch() {

TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);

globalTaskDispatcher.syncDispatch(new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “sync task1 run”);

}

});

HiLog.info(LABEL_LOG, “after sync task1”);

globalTaskDispatcher.syncDispatch(new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “sync task2 run”);

}

});

HiLog.info(LABEL_LOG, “after sync task2”);

globalTaskDispatcher.syncDispatch(new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “sync task3 run”);

}

});

HiLog.info(LABEL_LOG, “after sync task3”);

}

运行之后查看日志:

ff7b8964-1fc0-11ec-82a8-dac502259ad0.png

从运行结果我们可以看到,只有在当前线程等待任务执行完成之后才会继续往下执行,否则当前线程会被阻塞。

所以在使用 syncDispatch 的时候我们需要注意,如果对 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

派发任务,并立即返回,返回值是一个可用于取消任务的接口。

/**

* 异步派发任务

*/

private void asyncDispatch() {

TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);

Revocable revocable = globalTaskDispatcher.asyncDispatch(new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “async task1 run”);

}

});

HiLog.info(LABEL_LOG, “after async task1”);

}

运行之后查看日志:

0001850a-1fc1-11ec-82a8-dac502259ad0.png

从运行结果我们可以看到,只有在当前线程等待任务执行完成之后才会继续往下执行,否则当前线程会被阻塞,所以在使用。

③异步延迟派发任务 delayDispatch

异步执行,函数立即返回,内部会在延时指定时间后将任务派发到相应队列中。

延时时间参数仅代表在这段时间以后任务分发器会将任务加入到队列中,任务的实际执行时间可能晚于这个时间。

具体比这个数值晚多久,取决于队列及内部线程池的繁忙情况。

/**

* 异步延迟派发任务

*/

private void delayDispatch() {

final long callTime = System.currentTimeMillis();

final long delayTime = 50L;

TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);

Revocable revocable = globalTaskDispatcher.delayDispatch(new Runnable() {

@Override

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

}

运行之后查看日志:

00860d66-1fc1-11ec-82a8-dac502259ad0.png

从运行结果我们可以看出:

程序首先执行“after delayDispatch task1”

然后执行“delayDispatch task1 run”

最后执行“actualDelayTime 》= delayTime: %{public}b”, (actualDelay 》= delayTime)

这里 actualDelayTime 》= delayTime: true 可以看出延时时间参数仅代表在这段时间以后任务分发器会将任务加入到队列中,任务的实际执行时间可能晚于这个时间。

④任务组 Group

表示一组任务,且该组任务之间有一定的联系,由 TaskDispatcher 执行 createDispatchGroup 创建并返回。

将任务加入任务组,返回一个用于取消任务的接口。

/**

* 任务组

*/

private void dispatchGroup() {

String dispatcherName = “parallelTaskDispatcher”;

TaskDispatcher dispatcher = createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);

// 创建任务组。

Group group = dispatcher.createDispatchGroup();

// 将任务1加入任务组,返回一个用于取消任务的接口。

dispatcher.asyncGroupDispatch(group, new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “download task1 is running”);

}

});

// 将与任务1相关联的任务2加入任务组。

dispatcher.asyncGroupDispatch(group, new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “download task2 is running”);

}

});

// 在任务组中的所有任务执行完成后执行指定任务。

dispatcher.groupDispatchNotify(group, new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “the close task is running after all tasks in the group are completed”);

}

});

}

运行之后查看日志:

00fbdb4a-1fc1-11ec-82a8-dac502259ad0.png

⑤同步设置屏障任务 syncDispatchBarrier

在任务组上设立任务执行屏障,同步等待任务组中的所有任务执行完成,再执行指定任务。

/**

* 同步设置屏障任务

*/

private void syncDispatchBarrier() {

String dispatcherName = “parallelTaskDispatcher”;

TaskDispatcher dispatcher = createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);

// 创建任务组。

Group group = dispatcher.createDispatchGroup();

// 将任务加入任务组,返回一个用于取消任务的接口。

dispatcher.asyncGroupDispatch(group, new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “task1 is running”); // 1

}

});

dispatcher.asyncGroupDispatch(group, new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “task2 is running”); // 2

}

});

dispatcher.syncDispatchBarrier(new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “barrier”); // 3

}

});

HiLog.info(LABEL_LOG, “after syncDispatchBarrier”); // 4

}

运行之后查看日志:

01a4c066-1fc1-11ec-82a8-dac502259ad0.png

⑥异步设置屏障任务 asyncDispatchBarrier

在任务组上设立任务执行屏障后直接返回,指定任务将在任务组中的所有任务执行完成后再执行。

/**

* 异步设置屏障任务

*/

private void asyncDispatchBarrier() {

TaskDispatcher dispatcher = createParallelTaskDispatcher(“dispatcherName”, TaskPriority.DEFAULT);

// 创建任务组。

Group group = dispatcher.createDispatchGroup();

// 将任务加入任务组,返回一个用于取消任务的接口。

dispatcher.asyncGroupDispatch(group, new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “task1 is running”); // 1

}

});

dispatcher.asyncGroupDispatch(group, new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “task2 is running”); // 2

}

});

dispatcher.asyncDispatchBarrier(new Runnable() {

@Override

public void run() {

HiLog.info(LABEL_LOG, “barrier”); // 3

}

});

HiLog.info(LABEL_LOG, “after asyncDispatchBarrier”); // 4

}

运行之后查看日志:

02118cbe-1fc1-11ec-82a8-dac502259ad0.png

总结

线程它就像一面双刃剑,用的好的时候可以给我们带来事半功倍等效果,用的不好时就会给我们带来困扰。

并且这个困扰还不是一时半会能解决掉的(因为发现问题的时候,往往是到了需要优化期了,各项业务相互牵扯),故在项目初期就需要严格考虑考量这些问题了。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 线程
    +关注

    关注

    0

    文章

    504

    浏览量

    19674
  • 鸿蒙系统
    +关注

    关注

    183

    文章

    2634

    浏览量

    66299

原文标题:鸿蒙的线程管理,看完浑身通透!

文章出处:【微信号:gh_834c4b3d87fe,微信公众号:OpenHarmony技术社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    鸿蒙系统在服装RFID管理中的应用:打造智能零售新时代

    鸿蒙系统结合RFID技术,助力服装行业智能化升级,实现高效库存管理、自动化存取、全流程供应链管理,以及生产计件管理。常达智能物联提供高性能R
    的头像 发表于 07-15 14:57 257次阅读

    鸿蒙开发:线程模型

    FA模型下的线程主要有如下三类
    的头像 发表于 06-24 17:27 425次阅读
    <b class='flag-5'>鸿蒙</b>开发:<b class='flag-5'>线程</b>模型

    鸿蒙开发:【线程模型】

    管理其他线程的ArkTS引擎实例,例如使用TaskPool(任务池)创建任务或取消任务、启动和终止Worker线程
    的头像 发表于 06-13 16:38 392次阅读
    <b class='flag-5'>鸿蒙</b>开发:【<b class='flag-5'>线程</b>模型】

    千万不要忽略PCB设计中线宽线距的重要性

    中线宽线距的重要性: 1. 电气性能: 线宽和线距会影响电路板的电气性能。线宽决定了导线的电阻,线距则影响信号的串扰。正确选择线宽和线距可以确保电路板的信号完整性和稳定性。 2. 功率传输和热管理: 线宽的选择对于功率传输和热管理
    的头像 发表于 05-29 09:31 906次阅读
    千万不要忽略PCB设计<b class='flag-5'>中线</b>宽线距的重要性

    STM32F7使用FreeRTOS,程序运行一段时间后进入HardFault_Handler的原因?

    )”,“精准的数据访问冲突(PRECISERR)”。 其中工程中线程共6个。线程A每秒打印时间;线程B负责串口1发送命令;线程C负责接收串口1数据,并通过队列给
    发表于 04-08 07:23

    鸿蒙原生应用开发-ArkTS语言基础类库多线程TaskPool和Worker的对比(一)

    TaskPool偏向独立任务维度,该任务在线程中执行,无需关注线程的生命周期,超长任务(大于3分钟)会被系统自动回收;而Worker偏向线程的维度,支持长时间占据
    发表于 03-25 14:11

    什么是动态线程池?动态线程池的简单实现思路

    因此,动态可监控线程池一种针对以上痛点开发的线程管理工具。主要可实现功能有:提供对 Spring 应用内线程池实例的全局管控、应用运行时动态变更线
    的头像 发表于 02-28 10:42 628次阅读

    纯血鸿蒙系统,拿什么与安卓、iOS比?

    ArkUI …… 2、鸿蒙进阶 Stage模型 网络、数据管理 一次开发多段部署 …… 3、鸿蒙多媒体技术 音频 视频 相机 图片 …… 4、鸿蒙南向与驱动开发 物联网 驱动开发 ……
    发表于 02-21 21:04

    华为鸿蒙系统怎么样 华为鸿蒙系统和安卓系统的区别

    华为鸿蒙系统是华为公司自主研发的全场景分布式操作系统,于2019年8月首次发布。鸿蒙系统不同于传统的操作
    的头像 发表于 02-02 14:54 1696次阅读

    鸿蒙千帆起】高德地图携手HarmonyOS NEXT,开启智能出行新篇章

    德团队的辛勤努力和不懈探索。目前,高德地图在主图、信息展示、规划导航等基础功能方面已完成了鸿蒙化,未来还将逐步在鸿蒙系统上实现更多特色功能。 在实践分享环节,宋浩波深入剖析了高德地图在鸿蒙
    发表于 02-02 11:09

    如何在鸿蒙系统上安装Google Play

    随着鸿蒙(HarmonyOS)系统的逐渐普及和用户基数的增加,一些用户希望能在鸿蒙系统上使用Google Play商店以获取更多应用。然而,由于鸿蒙
    的头像 发表于 01-31 17:13 1.6w次阅读

    鸿蒙OS 线程管理开发指导

    场景介绍 如果应用的业务逻辑比较复杂,可能需要创建多个线程来执行多个任务。这种情况下,代码复杂难以维护,任务与线程的交互也会更加繁杂。要解决此问题,开发者可以使用“TaskDispatcher”来
    的头像 发表于 01-29 16:22 831次阅读

    三相四线制中中线的作用是什么

    三相四线制是一种电力供应系统,它由三个相互偏移120度的交流电相和一个中性线组成。中线在这种制度中起着重要的作用。下面将详细介绍中线在三相四线制中的作用。 首先,中线在电力
    的头像 发表于 01-18 16:52 5865次阅读

    鸿蒙系统和安卓的区别 鸿蒙系统有什么特别之处

    鸿蒙系统是华为公司自主研发的一款全新操作系统,旨在替代安卓系统鸿蒙系统与安卓
    的头像 发表于 01-18 11:45 1.2w次阅读

    mcu线程和进程的区别是什么

    MCU线程和进程是嵌入式系统中常见的并行执行的概念,它们之间有许多区别,包括线程与进程的定义、资源管理、通信机制、执行方式等等。下面将详细介绍MCU
    的头像 发表于 01-04 10:45 740次阅读