HarmonyOS 线程讲解(任务分发、线程通信)_鸿蒙开发线程怎么用(1)

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!


img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

⑧ 任务组(Group)

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

/** * 任务组 */
private void taskGroup(Context context) {
//创建并发任务分发器
TaskDispatcher dispatcher = context.createParallelTaskDispatcher(“parallelTaskDispatcher”, TaskPriority.DEFAULT);
//创建任务组
Group group = dispatcher.createDispatchGroup();
// 将任务 1 加入任务组,
dispatcher.asyncGroupDispatch(group,new Runnable() {
@Override public void run() {
HiLog.info(label,“download task1 is running”);
}
}
); // 将任务 2 加入任务组, dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override public void run() {
HiLog.info(label,“download task2 is running”); } }); // 在任务组中的所有任务执行完成后执行指定任务。
dispatcher.groupDispatchNotify(group, new Runnable() {
@Override public void run() {
HiLog.info(label, “the close task is running after all tasks in the group are completed”);
}
});
}

onStart方法中调用

运行效果如下,我运行了两次,两次日志是不一样的,如果里面执行的业务是不一样的,则耗时长的后完成。

⑨ 取消任务(Revocable)

Revocable 是取消一个异步任务的接口。异步任务包括通过 asyncDispatch、delayDispatch、asyncGroupDispatch 派发的任务。如果任务已经在执行中或执行完成,则会返回取消失败。

/** * 取消异步任务 */
private void revocableAsyncTask(Context context) {
TaskDispatcher dispatcher = context.getUITaskDispatcher();
Revocable revocable = dispatcher.delayDispatch(new Runnable() {
@Override
public void run() {
HiLog.info(label, “delay dispatch”);
}
},
10);
boolean revoked = revocable.revoke(); HiLog.info(label, “” + revoked);
}

在onStart()中调用

//取消异步任务revocableAsyncTask(MainAbility.this);

运行效果如下:

⑩ 同步设置屏障任务 (syncDispatchBarrier)

在任务组上设立任务执行屏障,同步等待任务组中的所有任务执行完成,再执行指定任务。在全局并发任务分发器(GlobalTaskDispatcher)上同步设置任务屏障,将不会起到屏障作用。就比如说考试提前交卷,A提前20分钟,B提前10分钟,但你只是离开了考室,离不开考场,这个考场的门就是这个屏障,无论你是提前多久,你都要等到所有考生考完,老师收卷之后才能离开考场,就是这么一个理。代码如下:

/** * 同步设置屏障任务 */
private void setSyncDispatchBarrier(Context context) {
TaskDispatcher dispatcher = context.createParallelTaskDispatcher(“parallelTask”,TaskPriority.DEFAULT);
//创建任务组
Group group = dispatcher.createDispatchGroup(); //将任务1加入任务组
dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override public void run() {
HiLog.info(label,“task1 is running”);
}
}); //将任务2加入任务组
dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override public void run() {
HiLog.info(label,“task2 is running”);
}
});
dispatcher.asyncDispatchBarrier(new Runnable() {
@Override public void run() {
HiLog.info(label,“Barrier”);
}
});
HiLog.info(label,“after syncDispatchBarrier”);
}

在onStart()中调用,

//同步设置屏障任务setSyncDispatchBarrier(MainAbility.this);

运行

⑪ 异步设置屏障任务 (asyncDispatchBarrier)

在任务组上设立任务执行屏障后直接返回,指定任务将在任务组中的所有任务执行完成后再执行。在全局并发任务分发器(GlobalTaskDispatcher)上异步设置任务屏障,将不会起到屏障作用。可以使用并发任务分发器(ParallelTaskDispatcher)分离不同的任务组,达到微观并行、宏观串行的行为。

/** * 异步设置屏障任务 */
private void setAsyncDispatchBarrier(Context context) {
TaskDispatcher dispatcher = context.createParallelTaskDispatcher(“AsyncParallelTaskDispatcher”, TaskPriority.DEFAULT); // 创建任务组
Group group = dispatcher.createDispatchGroup(); //将任务1加入任务组
dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override public void run() {
HiLog.info(label, “task1 is running”); // 1
}
});
//将任务2加入任务组 dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override public void run() {
HiLog.info(label, “task2 is running”); // 2
} });
dispatcher.asyncDispatchBarrier(new Runnable() {
@Override public void run() {
HiLog.info(label, “barrier”); // 3
} });
HiLog.info(label, “after syncDispatchBarrier”); // 4
}

在onStart()中调用

//异步设置屏障任务setAsyncDispatchBarrier(MainAbility.this);

运行效果

⑫ 执行多次任务(applyDispatch)

对指定任务执行多次

/** * 执行多次任务 */ p
rivate void multipleTasks() { //总执行次数
final int total = 10; //倒数计时器
final CountDownLatch latch = new CountDownLatch(total); //长整形列表数组
final ArrayList indexList = new ArrayList<>(total); TaskDispatcher dispatcher = createParallelTaskDispatcher(“dispatcher”, TaskPriority.DEFAULT); //执行多次任务
dispatcher.applyDispatch((index) -> {
indexList.add(index); latch.countDown();
HiLog.info(label, "long: "+index); },
total);
//设置任务超时
try { latch.await(); }
catch (InterruptedException e) {
HiLog.info(label, “latch exception”);
} //返回true则说明执行了10次
HiLog.info(label, “list size matches,” + (total == indexList.size()));
}

运行效果如下:

三、线程通信

在开发过程中,开发者经常需要在当前线程中处理下载任务等较为耗时的操作,但是又不希望当前的线程受到阻塞。此时,就可以使用 EventHandler 机制。EventHandler 是HarmonyOS 用于处理线程间通信的一种机制,可以通过 EventRunner 创建新线程,将耗时的操作放到新线程上执行。这样既不阻塞原来的线程,任务又可以得到合理的处理。比如:主线程使用 EventHandler 创建子线程,子线程做耗时的下载图片操作,下载完成后,子线程通过 EventHandler 通知主线程,主线程再更新 UI。

① EventRunner

EventRunner 是一种事件循环器,循环处理从该 EventRunner 创建的新线程的事件队列中获取 InnerEvent 事件或者 Runnable 任务。InnerEvent 是 EventHandler 投递的事件。

EventHandler 是一种用户在当前线程上投递 InnerEvent 事件或者 Runnable 任务到异步线程上处理的机制。每一个 EventHandler 和指定的 EventRunner 所创建的新线程绑定,并且该新线程内部有一个事件队列。EventHandler 可以投递指定的 InnerEvent 事件或 Runnable 任务到这个事件队列。EventRunner 从事件队列里循环地取出事件,如果取出的事件是InnerEvent 事件,将在 EventRunner 所在线程执行 processEvent 回调;如果取出的事件是Runnable 任务,将在 EventRunner 所在线程执行 Runnable 的 run 回调。

② EventHandler

EventHandler 有两个主要作用:

在不同线程间分发和处理 InnerEvent 事件或 Runnable 任务。

延迟处理 InnerEvent 事件或 Runnable 任务。

EventHandler 的运作机制如下图所示:

使用 EventHandler 实现线程间通信的主要流程:

EventHandler 投递具体的 InnerEvent 事件或者 Runnable 任务到 EventRunner 所创建的线程的事件队列。

EventRunner 循环从事件队列中获取 InnerEvent 事件或者 Runnable 任务。

处理事件或任务:

① 如果 EventRunner 取出的事件为 InnerEvent 事件,则触发 EventHandler 的回调方法并触发 EventHandler 的处理方法,在新线程上处理该事件。

② 如果 EventRunner 取出的事件为 Runnable 任务,则 EventRunner 直接在新线程上处理 Runnable 任务。

1. 约束限制

在进行线程间通信的时候,EventHandler 只能和 EventRunner 所创建的线程进行绑定,EventRunner 创建时需要判断是否创建成功,只有确保获取的 EventRunner 实例非空时,才可以使用 EventHandler 绑定 EventRunner。

一个 EventHandler 只能同时与一个 EventRunner 绑定,一个 EventRunner 上可以创建多个 EventHandler。

2. 开发场景

EventHandler 的主要功能是将 InnerEvent 事件或者 Runnable 任务投递到其他的线程进行处理,其使用的场景包括

开发者需要将 InnerEvent 事件投递到新的线程,按照优先级和延时进行处理。投递时,EventHandler 的优先级可在IMMEDIATE、HIGH、LOW、IDLE 中选择,并设置合适的 delayTime。

开发者需要将 Runnable 任务投递到新的线程,并按照优先级和延时进行处理。投递时,EventHandler 的优先级可在IMMEDIATE、HIGH、LOW、IDLE 中选择,并设置合适的 delayTime。

开发者需要在新创建的线程里投递事件到原线程进行处理。

3. 工作模式

EventRunner 的工作模式可以分为托管模式和手动模式。两种模式是在调用 EventRunner 的create()方法时,通过选择不同的参数来实现的,默认为托管模式。

托管模式:不需要开发者调用 run()和 stop()方法去启动和停止 EventRunner。当 EventRunner 实例化时,系统调用

run()来启动 EventRunner;当 EventRunner 不被引用时,系统调用 stop()来停止 EventRunner。

手动模式:需要开发者自行调用 EventRunner 的 run()方法和 stop()方法来确保线程的启动和停止。

③ 接口说明
1. EventHandler

EventHandler 的属性 Priority(优先级)介绍:

EventRunner 将根据优先级的高低从事件队列中获取事件或者 Runnable 任务进行处理。

属性描述
Priority.IMMEDIATE表示事件被立即投递
Priority.HIGH表示事件先于 LOW 优先级投递
Priority.LOW表示事件优于 IDLE 优先级投递,事件的默认优先级是 LOW
Priority.IDLE表示在没有其他事件的情况下,才投递该事件
  • EventHandler 的主要接口介绍:

2. EventRunner
  • EventRunner 的主要接口介绍:

3. InnerEvent
  • InnerEvent 的属性介绍:
属性描述
eventId事件的 ID, 由开发者定义用来辨别事件
object事件携带的 Object 信息
param事件携带的 long 型数据
  • InnerEvent 的主要接口介绍:

④ 开发步骤
一、EventHandler 投递 InnerEvent 事件

EventHandler 投递 InnerEvent 事件,并按照优先级和延时进行处理,创建一个MyEventHandler类型继承EventHandler

package com.llw.thread.event;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MyEventHandler extends EventHandler {
/** * 日志 */
private static final HiLogLabel label = new HiLogLabel(3, 0xD001100, “ThreadDemo”);
public MyEventHandler(EventRunner runner)
throws IllegalArgumentException { super(runner);
}
/** * 1. 创建 EventHandler 的子类,在子类中重写实现方法 processEvent()来处理事件 *
* @param event */
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
if (event == null) { return; }
int eventId = event.eventId;
long param = event.param;
switch ((int) (eventId | param)) {
case 1: HiLog.info(label, “eventId | param —>” + 1);
break;
default: break; }
} /** * EventHandler 投递 InnerEvent 事件 */
private void initInnerEvent() {
//2. 创建 EventRunner,以手动模式为例。
// create()的参数是 true 时,则为托管模式
EventRunner runner = EventRunner.create(false);
if (runner == null) { return; } //3. 创建 EventHandler 子类的实例。
MyEventHandler myHandler = new MyEventHandler(runner); //4. 获取 InnerEvent 事件。
int eventId1 = 0;
int eventId2 = 1;
long param = 0;
Object object = null;
InnerEvent event1 = InnerEvent.get(eventId1, param, object);
InnerEvent event2 = InnerEvent.get(eventId2, param, object); //5. 投递事件,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.sendEvent(event1, 0, EventHandler.Priority.IMMEDIATE); // 延时 2ms 后立即处理
myHandler.sendEvent(event2, 2, EventHandler.Priority.IMMEDIATE); //6. 启动和停止 EventRunner,如果为托管模式,则不需要此步骤。
runner.run(); //待执行操作
// … 执行业务逻辑
// 停止
EventRunner runner.stop();
}
}

二、EventHandler 投递 Runnable 任务

/** * EventHandler 投递 Runnable 任务 */
private void initRunnable() {
//2. 创建 EventRunner,以手动模式为例。
// create()的参数是 true 时,则为托管模式
EventRunner runner = EventRunner.create(false); if (runner == null) { return; }
//3. 创建 EventHandler 子类的实例。
MyEventHandler myHandler = new MyEventHandler(runner);
//2. 创建 Runnable 任务。
Runnable task1 = new Runnable() {
@Override public void run() { HiLog.info(label, “task1 running”); } };
Runnable task2 = new Runnable() {
@Override public void run() {
HiLog.info(label, “task1 running”);
}
}; //3. 投递 Runnable 任务,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.postTask(task1, 0, EventHandler.Priority.IMMEDIATE); // 延时 2ms 后立即执行
myHandler.postTask(task2, 2, EventHandler.Priority.IMMEDIATE); //4. 启动和停止 EventRunner,如果是托管模式,则不需要此步骤。 runner.run();
//待执行操作
// … 执行业务逻辑
// 停止
EventRunner runner.stop();
}

三、在新创建的线程里投递事件到原线程

修改MyEventHandler之后代码如下:

package com.llw.thread.event;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MyEventHandler extends EventHandler {
/** * 日志 */
private static final HiLogLabel label = new HiLogLabel(3, 0xD001100, “ThreadDemo”);
private MyEventHandler myHandler;
private EventRunner runner;
public MyEventHandler(EventRunner runner) throws IllegalArgumentException {
super(runner); } /** * 1. 创建 EventHandler 的子类,在子类中重写实现方法 processEvent()来处理事件 * * @param event */ @Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
if (event == null) { return; }
int eventId = event.eventId;
long param = event.param;
Object object = event.object; switch ((int) (eventId | param)) {
case 1: HiLog.info(label, “eventId | param —>” + 1);
break;
case 2: EventRunner runner2 = null; // 将原先线程的 EventRunner 实例投递给新创建的线程
if (object instanceof EventRunner) {
//强转 runner2 = (EventRunner) object;
} // 将原先线程的 EventRunner 实例与新创建的线程的 EventHandler 绑定
EventHandler myHandler2 = new EventHandler(runner2) {
@Override protected void processEvent(InnerEvent event) {
//需要在原先线程执行的操作
}
};
int eventId2 = 1; long param2 = 0;
Object object2 = null;
InnerEvent event2 = InnerEvent.get(eventId2, param2, object2); // 投递事件到原先的线程
myHandler2.sendEvent(event2);
break; default: break; }
} /** * EventHandler 投递 InnerEvent 事件 */
private void initInnerEvent() {
//2. 创建 EventRunner,以手动模式为例。 // create()的参数是 true 时,则为托管模式
runner = EventRunner.create(false);
if (runner == null) { return; } //3. 创建 EventHandler 子类的实例。
myHandler = new MyEventHandler(runner);
//4. 获取 InnerEvent 事件。
int eventId1 = 0;
int eventId2 = 1;
long param = 0;
Object object = null;
InnerEvent event1 = InnerEvent.get(eventId1, param, object);
InnerEvent event2 = InnerEvent.get(eventId2, param, object);
//5. 投递事件,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.sendEvent(event1, 0, EventHandler.Priority.IMMEDIATE); // 延时 2ms 后立即处理
myHandler.sendEvent(event2, 2, EventHandler.Priority.IMMEDIATE); //6. 启动和停止 EventRunner,如果为托管模式,则不需要此步骤。

runner.run();

//待执行操作 // … 执行业务逻辑
// 停止 EventRunner runner.stop(); } /
** * EventHandler 投递 Runnable 任务 */
private void initRunnable() {
//2. 创建 EventRunner,以手动模式为例。 // create()的参数是 true 时,则为托管模式
runner = EventRunner.create(false);
if (runner == null) { return; }
//3. 创建 EventHandler 子类的实例。
myHandler = new MyEventHandler(runner); //2. 创建 Runnable 任务。
Runnable task1 = new Runnable() {
@Override public void run() {
HiLog.info(label, “task1 running”);
} };
Runnable task2 = new Runnable() {
@Override public void run() {
HiLog.info(label, “task1 running”);
}
}; //3. 投递 Runnable 任务,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.postTask(task1, 0, EventHandler.Priority.IMMEDIATE); // 延时 2ms 后立即执行
myHandler.postTask(task2, 2, EventHandler.Priority.IMMEDIATE);
//4. 启动和停止 EventRunner,如果是托管模式,则不需要此步骤。 runner.run();
//待执行操作
// … 执行业务逻辑
// 停止 EventRunner runner.stop(); } /
** * 在新创建的线程里投递事件到原线程 */

private void initNewToOld() {
//2. 创建 EventRunner,以手动模式为例。
// create()的参数是 true 时,则为托管模式。
EventRunner runner1 = EventRunner.create(false);
// 需要对 EventRunner 的实例进行校验,不是任何线程都可以通过 create 创建,例如:当线程池已满时,不能再创建线程。
if (runner1 == null) { return; } //3. 创建 EventHandler 子类的实例。
MyEventHandler myHandler1 = new MyEventHandler(runner1);
//4. 获取 InnerEvent 事件。
// 获取事件实例,其属性 eventId, param, object 由开发者确定,代码中只是示例。
int eventId1 = 0; long param = 0;
Object object = (Object) EventRunner.current();
InnerEvent event1 = InnerEvent.get(eventId1, param, object);
//5. 投递事件,在新线程上直接处理。
// 将与当前线程绑定的 EventRunner 投递到与 runner1 创建的新线程中 myHandler.sendEvent(event1);
//6. 启动和停止 EventRunner,如果是托管模式,则不需要此步骤。 runner.run();
//待执行操作
// … 执行业务逻辑
// 停止
EventRunner runner.stop();
}
}

为了能让大家更好的学习鸿蒙 (OpenHarmony) 开发技术,这边特意整理了《鸿蒙 (OpenHarmony)开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙 (OpenHarmony)开发学习手册》

入门必看:https://qr21.cn/FV7h05
  1. 应用开发导读(ArkTS)
  2. ……

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!


img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

ArkTS)
2. ……

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!


[外链图片转存中…(img-PfoH7x4n-1715293209598)]
[外链图片转存中…(img-vznpd9cS-1715293209598)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

  • 29
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值