2024年HarmonyOS鸿蒙最全鸿蒙 线程讲解(任务分发、线程通信)(2),2024HarmonyOS鸿蒙开发社招面试总结

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

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

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

}

在运行一下:

在这里插入图片描述

很明显里面的任务已经撤销了、

⑦ 异步延迟派发任务(delayDispatch)

异步延迟派发任务:异步执行,函数立即返回,内部会在延时指定时间后将任务派发到相应队列中。延时时间参数仅代表在这段时间以后任务分发器会将任务加入到队列中,任务的实际执行时间可能晚于这个时间。具体比这个数值晚多久,取决于队列及内部线程池的繁忙情况。下面用代码演示一下:

/**

  • 当前时间

*/

final long currentTime = System.currentTimeMillis();

/**

  • 延迟时间 100ms

*/

final long delayTime = 100;

在这里插入图片描述

delayTask方法如下:

/**

  • GlobalTaskDispatcher 派发异步延时任务

*/

private void delayTask() {

globalTaskDispatcher.delayDispatch(new Runnable() {

@Override

public void run() {

HiLog.info(label, “delay task1 run”);

final long actualDelayMs = System.currentTimeMillis() - currentTime;

HiLog.info(label,"actualDelayTime >= delayTime : " + (actualDelayMs >= delayTime));

}

},delayTime);

HiLog.info(label, “after delay task1”);

}

日志如下:

在这里插入图片描述

⑧ 任务组(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 是取消一个异步任务的接口。异步任务包括通过 asyncDispatchdelayDispatchasyncGroupDispatch 派发的任务。如果任务已经在执行中或执行完成,则会返回取消失败。

/**

  • 取消异步任务

*/

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)

对指定任务执行多次

/**

  • 执行多次任务

*/

private 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 实现线程间通信的主要流程:

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

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

  3. 处理事件或任务:

① 如果 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 的主要接口介绍:

| 接口名 | 描述 |

| — | — |

| EventHandler(EventRunner runner) | 利用已有的 EventRunner 来创建 EventHandler |

| current() | 在 processEvent 回调中,获取当前的 EventHandler |

| processEvent(InnerEvent event) | 回调处理事件,由开发者实现 |

| sendEvent(InnerEvent event) | 发送一个事件到事件队列,延时为 0ms, 优先级为 LOW |

| sendEvent(InnerEvent event, long delayTime) | 发送一个延时事件到事件队列,优先级为 LOW |

| sendEvent(InnerEvent event, long delayTime, EventHandler.Priority priority) | 发送一个指定优先级的延时事件到事件队列 |

| sendEvent(InnerEvent event, EventHandler.Priority priority) | 发送一个指定优先级的事件到事件队列,延时为 0ms |

| sendSyncEvent(InnerEvent event) | 发送一个同步事件到事件队列,延时为 0ms,优先级为 LOW |

| sendSyncEvent(InnerEvent event, EventHandler.Priority priority) | 发送一个指定优先级的同步事件到事件队列,延时为 0ms,优先级不可以是 IDLE |

| postSyncTask(Runnable task) | 发送一个 Runnable 同步任务到事件队列,延时为 0ms, 优先级为 LOW |

| postSyncTask(Runnable task, EventHandler.Priority priority) | 发送一个指定优先级的 Runnable 同步任务到事件队列,延时为0ms |

| postTask(Runnable task) | 发送一个 Runnable 任务到事件队列,延时为 0ms,优先级为LOW |

| postTask(Runnable task, long delayTime) | 发送一个 Runnable 延时任务到事件队列,优先级为 LOW |

| postTask(Runnable task, long delayTime, EventHandler.Priority priority) | 发送一个指定优先级的 Runnable 延时任务到事件队列 |

| postTask(Runnable task, EventHandler.Priority priority) | 发送一个指定优先级的 Runnable 任务到事件队列,延时为 0ms |

| sendTimingEvent(InnerEvent event, long taskTime) | 发送一个定时事件到队列,在 taskTime 时间执行,如果taskTime 小于当前时间,立即执行,优先级为 LOW |

| sendTimingEvent(InnerEvent event, long taskTime,EventHandler.Priority priority) | 发送一个带优先级的事件到队列,在 taskTime 时间执行,如果 |

| taskTime 小于当前时间,立即执行postTimingTask(Runnable task, long taskTime) | 发送一个 Runnable 任务到队列,在 taskTime 时间执行,如果taskTime 小于当前时间,立即执行,优先级为 LOW |

| postTimingTask(Runnable task, long taskTime,EventHandler.Priority priority) | 发送一个带优先级的 Runnable 任务到队列,在 taskTime 时间执行,如果 taskTime 小于当前时间,立即执行 |

| removeEvent(int eventId) | 删除指定 id 的事件 |

| removeEvent(int eventId, long param) | 删除指定 id 和 param 的事件 |

| removeEvent(int eventId, long param, Object object) | 删除指定 id、param 和 object 的事件 |

| removeAllEvent() | 删除该 EventHandler 的所有事件 |

| getEventName(InnerEvent event) | 获取事件的名字 |

| getEventRunner() | 获取该 EventHandler 绑定的 EventRunner |

| isIdle() | 判断队列是否为空 |

| hasInnerEvent(Runnable runnable) | 是否有还未被处理的这个任务 |

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

| 接口名 | 描述 |

| — | — |

| create() | 创建一个拥有新线程的 EventRunner |

| create(boolean isDeposited) | 创建一个拥有新线程的 EventRunner,isDeposited 为 true 时,EventRunner 为托管模式,系统将自动管理该 EventRunner;isDeposited 为 false 时,EventRunner 为手动模式。 |

| create(String newThreadName) | 创建一个拥有新线程的 EventRunner, 新线程的名字是 newThreadName |

| current() | 获取当前线程的 EventRunner |

| run() | EventRunner 为手动模式时,调用该方法启动新的线程 |

| stop() | EventRunner 为手动模式时,调用该方法停止新的线程 |

3. InnerEvent
  • InnerEvent 的属性介绍:

| 属性 | 描述 |

| — | — |

| eventId | 事件的 ID, 由开发者定义用来辨别事件 |

| object | 事件携带的 Object 信息 |

| param | 事件携带的 long 型数据 |

  • InnerEvent 的主要接口介绍:

| 接口名 | 描述 |

| — | — |

| drop() | 释放一个事件实例 |

| get() | 获得一个事件实例 |

| get(int eventId) | 获得一个指定的 eventId 的事件实例 |

| get(int eventId, long param) | 获得一个指定的 eventId 和 param 的事件实例 |

| get(int eventId, long param, Object object) | 获得一个指定的 eventId,param 和 object 的事件实例 |

| get(int eventId, Object object) | 获得一个指定的 eventId 和 object 的事件实例 |

| PacMap getPacMap() | 获取 PacMap,如果没有,会新建一个 |

| Runnable getTask() | 获取 Runnable 任务 |

| PacMap peekPacMap() | 获取 PacMap |

| void setPacMap(PacMap pacMap) | 设置 PacMap |

④ 开发步骤

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

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


img
img

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

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

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

/**

  • 日志

*/

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

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


[外链图片转存中…(img-XNgABFmw-1715235358435)]
[外链图片转存中…(img-yzBrY9Rr-1715235358436)]

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值