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

    文章

    489

    浏览量

    19495
  • 鸿蒙系统
    +关注

    关注

    183

    文章

    2606

    浏览量

    65270

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

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

收藏 人收藏

    评论

    相关推荐

    鸿蒙APP开发:【ArkTS类库多线程】TaskPool和Worker的对比(2)

    创建Worker的线程称为宿主线程(不一定是主线程,工作线程也支持创建Worker子线程),Worker自身的
    的头像 发表于 03-27 15:44 118次阅读
    <b class='flag-5'>鸿蒙</b>APP开发:【ArkTS类库多<b class='flag-5'>线程</b>】TaskPool和Worker的对比(2)

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

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

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

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

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

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

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

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

    鸿蒙OS 线程管理开发指导

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

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

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

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

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

    线程池的创建方式有几种

    线程池是一种用于管理和调度线程的技术,能够有效地提高系统的性能和资源利用率。它通过预先创建一组线程并维护一个工作队列,将任务提交给
    的头像 发表于 12-04 16:52 410次阅读

    核心线程数和最大线程数怎么设置

    核心线程数和最大线程数是Java线程池中重要的参数,用来控制线程中线程的数量和行为。正确地设置这两个参数可以优化
    的头像 发表于 12-01 13:50 4072次阅读

    华为鸿蒙系统

    华为鸿蒙系统(HUAWEI Harmony OS),是华为公司在2019年8月9日于东莞举行的华为开发者大会(HDC.2019)上正式发布的操作系统。 华为鸿蒙
    发表于 11-02 19:39

    Java中的线程池包括哪些

    线程池是用来统一管理线程的,在 Java 中创建和销毁线程都是一件消耗资源的事情,线程池可以重复使用线程
    的头像 发表于 10-11 15:33 559次阅读
    Java中的<b class='flag-5'>线程</b>池包括哪些

    鸿蒙操作系统的前世今生

    01、 鸿蒙操作系统发展沿革 鸿蒙这个名字意为“万物起源”,同时也寓意国产操作系统的开端。鸿蒙操作系统
    发表于 10-08 19:55

    如何用C++实现一个线程池呢?

    C++线程池是一种多线程管理模型,把线程分成任务执行和线程调度两部分。
    发表于 06-08 14:53 794次阅读
    如何用C++实现一个<b class='flag-5'>线程</b>池呢?

    在Java中的线程状态转换

    在 Java 中线程的生命周期中一共有 6 种状态。New(新创建);Runnable(可运行);Blocked(被阻塞);Waiting(等待);Timed Waiting(计时等待);Terminated(被终止)。
    的头像 发表于 06-02 10:07 402次阅读
    在Java中的<b class='flag-5'>线程</b>状态转换