同时执行多个任务。
--------------------------> 任务1
--------------------------> 任务2
--------------------------> 任务3
依次执行多个任务。
任务1 任务2 任务3
-------->-------->-------->
在多个任务之间轮流切换,宏观看是并行的,微观则是串行的。
---- ---- --> 任务1
---- ---- > 任务2
---- ---- > 任务3
一个任务必须等待另一个任务执行完以后再继续执行。
----- -----> 任务1
----- -----> 任务2
----> 任务3
一个任务无须等待另一个任务执行完即可以继续执行。
--------------------------> 任务1
---------------> 任务2
----> 任务3
在启动应用时,系统会为该应用创建一个被称为主线程的执行过程。该执行过程随应用的启动而创建,随应用的终止而销毁,是应用的核心线程。用户界面的显示和更新等操作都是在主线程中完成的,因此主线程亦称UI线程。默认情况下,应用的所有操作都是在主线程中执行的。
如果需要执行比较耗时的任务,如下载文件、访问数据库等,为了不使用户界面因主线程被阻塞和出现卡顿,影响用户体验,甚至迟滞其它任务的执行,可以将这些耗时任务放在独立于主线程之外的辅助线程中执行。
Java语言本身提供了完善的多线程机制,是实现并发的重要技术手段,包含基本的Thread类和Runnable接口。但随着应用的业务逻辑变得越来越复杂,很多时候往往需要创建多个辅助线程,并发执行多个任务。线程之间可能还需要交换数据和同步进度。程序代码会因此变得异常复杂且难以维护。为了简化多线程应用的开发,鸿蒙系统提供了两种机制,帮助解决线程管理问题:
在鸿蒙中,除了使用Java的Thread类和Runnable接口实现多线程以外,还可以借助任务分发器(TaskDispatcher)实现在不同线程中的任务分发。TaskDispatcher是一个Java接口(Interface),也是Ability分发任务的基本接口。
鸿蒙中的线程并不是平等的,而是被分为三个优先级,定义在TaskPriority枚举中:
在主线程上执行的任务默认拥有最高优先级。如果某个任务并不急于获得结果,采用较低的优先级更为合理。
作为接口的TaskDispatcher拥有多个实现,每个实现对应不同的任务分发策略。在分发任务时可以指定任务的优先级,由同一个任务分发器分发的任务优先级相同。
TaskDispatcher
|
|___GlobalTaskDispatcher - 全局任务分发器
|___ParallelTaskDispatcher - 并行任务分发器
|___SerialTaskDispatcher - 串行任务分发器
|___SpecTaskDispatcher - 专有任务分发器
专有任务分发器是绑定到专有线程上的任务分发器。目前已有的专有线程是主线程,即UI线程。
SpecTaskDispatcher
|
|___MainTaskDispatcher - 主线程专有任务分发器 \
| > 它们其实是一样的
|___UITaskDispatcher - UI线程专有任务分发器 / <-建议使用这个
默认情况下主线程不能执行过多任务,通过这个分发器就可以将任务绑定到主线程上,使之执行更多的任务。
默认情况下UI线程不能执行过多任务,通过这个分发器就可以将任务绑定到UI线程上,使之执行更多的任务。
taskDispatcher.asyncDispatch(new Runnable() { @Override public void run() { // 更新界面 } });
在获得或创建以上各种任务分发器对象之后,即可通过调用其中的方法,在线程中分发任务。
分发任务并在当前线程等待任务完成。表示任务的run()方法返回前,当前线程会阻塞。
taskDispatcher.syncDispatch(new Runnable() { @Override public void run() { // 执行任务 } });
同步分发使用不当极易导致线程死锁:
分发任务并立即返回一个用于取消该任务的接口(Revocable)。
Revocable revocable = taskDispatcher.asyncDispatch(new Runnable() { @Override public void run() { // 执行任务 } });
所返回的Revocable对象可被用于取消任务。
分发任务并立即返回一个用于取消该任务的接口(Revocable)。系统内部会在指定时间后将任务排入等候队列。所指定的延迟时间仅表示任务入队的时间,任务实际被执行的时间可能晚于这个时间,具体晚多久取决于等候队列的长度及内部线程池的繁忙程度。
Revocable revocable = taskDispatcher.delayDispatch(new Runnable() { @Override public void run() { // 执行任务 } }, 5000); ^ |__延迟时间毫秒值
所返回的Revocable对象可被用于取消任务。
任务组由彼此存在某种联系的多个任务组成。可以指定在组内任务都执行完以后执行的终结任务。
Group group = taskDispatcher.createDispatchGroup(); Revocable revocable1 = taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { // 一号任务 } }); Revocable revocable2 = taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { // 二号任务 } }); taskDispatcher.groupDispatchNotify(group, new Runnable() { @Override public void run() { // 终结任务 } });
所返回的Revocable对象可被用于取消任务。
只有asyncDispatch()、delayDispatch()和asyncGroupDispatch()三个方法,返回Revocable对象,也只有通过这三个方法分发的异步任务,才能被取消。
boolean revoked = revocable.revoke();
只能取消尚未开始执行的任务,无法取消正在执行或已经完成的任务,对于后者revoke()返回false。
在任务组上设置屏障,在任务组中的所有任务完成后执行屏障任务,并在完成后返回。
Group group = taskDispatcher.createDispatchGroup(); Revocable revocable1 = taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { // 一号任务 } }); Revocable revocable2 = taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { // 二号任务 } }); taskDispatcher.syncDispatchBarrier(new Runnable() { @Override public void run() { // 屏障任务 } });
不能通过全局任务分发器(GlobalTaskDispatcher)同步分发屏障任务。
在任务组上设置屏障并立即返回,在任务组中的所有任务完成后执行屏障任务。
Group group = taskDispatcher.createDispatchGroup(); Revocable revocable1 = taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { // 一号任务 } }); Revocable revocable2 = taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { // 二号任务 } }); taskDispatcher.asyncDispatchBarrier(new Runnable() { @Override public void run() { // 屏障任务 } });
不能通过全局任务分发器(GlobalTaskDispatcher)异步分发屏障任务。
在异步组分发的基础上设置更多的等候节点,即屏障任务。
Group group = taskDispatcher.createDispatchGroup(); Revocable revocable1 = taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { // 一号任务 } }); Revocable revocable2 = taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { // 二号任务 } }); taskDispatcher.groupDispatchBarrier(group, new Runnable() { @Override public void run() { // 屏障任务 } Revocable revocable3 = taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { // 三号任务 } }); Revocable revocable4 = taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { // 四号任务 } }); taskDispatcher.groupDispatchNotify(group, new Runnable() { @Override public void run() { // 终结任务 }
此方法仅限于在并行任务分发器(ParallelTaskDispatcher)上使用。
终结任务也可以理解为一种屏障任务,故也可以通过groupDispatchBarrier()方法分发。
以异步方式多次执行同一个任务。
taskDispatcher.applyDispatch(new Consumer<Long>() { @Override public void accept(Long index) { // 执行任务 ^ } |__第几次执行 }, 3); ^ |__执行次数
例程:Task
...\Task\entry\src\main\resources\base\graphic\background_button.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:shape="rectangle"> <corners ohos:radius="100"/> <solid ohos:color="#00a2e8"/> </shape>
...\Task\entry\src\main\resources\base\layout\ability_main.xml
<?xml version="1.0" encoding="utf-8"?> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:left_padding="60vp" ohos:right_padding="60vp" ohos:alignment="center" ohos:orientation="vertical" ohos:background_element="#000000"> <Button ohos:id="$+id:btnSyncDispatch" ohos:height="match_content" ohos:width="match_parent" ohos:padding="8vp" ohos:background_element="$graphic:background_button" ohos:text="同步分发" ohos:text_size="24fp" ohos:text_color="#ffffff" /> <Button ohos:id="$+id:btnAsyncDispatch" ohos:height="match_content" ohos:width="match_parent" ohos:padding="8vp" ohos:top_margin="10vp" ohos:background_element="$graphic:background_button" ohos:text="异步分发" ohos:text_size="24fp" ohos:text_color="#ffffff" /> <Button ohos:id="$+id:btnDelayDispatch" ohos:height="match_content" ohos:width="match_parent" ohos:padding="8vp" ohos:top_margin="10vp" ohos:background_element="$graphic:background_button" ohos:text="异步延迟分发" ohos:text_size="24fp" ohos:text_color="#ffffff" /> <Button ohos:id="$+id:btnAsyncGroupDispatch" ohos:height="match_content" ohos:width="match_parent" ohos:padding="8vp" ohos:top_margin="10vp" ohos:background_element="$graphic:background_button" ohos:text="异步组分发" ohos:text_size="24fp" ohos:text_color="#ffffff" /> <Button ohos:id="$+id:btnRevoke" ohos:height="match_content" ohos:width="match_parent" ohos:padding="8vp" ohos:top_margin="10vp" ohos:background_element="$graphic:background_button" ohos:text="取消任务" ohos:text_size="24fp" ohos:text_color="#ffffff" /> <Button ohos:id="$+id:btnSyncDispatchBarrier" ohos:height="match_content" ohos:width="match_parent" ohos:padding="8vp" ohos:top_margin="10vp" ohos:background_element="$graphic:background_button" ohos:text="同步分发屏障" ohos:text_size="24fp" ohos:text_color="#ffffff" /> <Button ohos:id="$+id:btnAsyncDispatchBarrier" ohos:height="match_content" ohos:width="match_parent" ohos:padding="8vp" ohos:top_margin="10vp" ohos:background_element="$graphic:background_button" ohos:text="异步分发屏障" ohos:text_size="24fp" ohos:text_color="#ffffff" /> <Button ohos:id="$+id:btnApplyDispatch" ohos:height="match_content" ohos:width="match_parent" ohos:padding="8vp" ohos:top_margin="10vp" ohos:background_element="$graphic:background_button" ohos:text="异步多次分发" ohos:text_size="24fp" ohos:text_color="#ffffff" /> </DirectionalLayout>
...\Task\entry\src\main\java\com\minwei\task\slice\MainAbilitySlice.java
public class MainAbilitySlice extends AbilitySlice { private static final HiLogLabel label = new HiLogLabel( HiLog.LOG_APP, 0x00101, "Task"); private final Calendar calendar = Calendar.getInstance(); private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss.SSS"); @Override public void onStart(Intent intent) { ... findComponentById(ResourceTable.Id_btnSyncDispatch) .setClickedListener(component -> syncDispatch()); findComponentById(ResourceTable.Id_btnAsyncDispatch) .setClickedListener(component -> asyncDispatch()); findComponentById(ResourceTable.Id_btnDelayDispatch) .setClickedListener(component -> delayDispatch()); findComponentById(ResourceTable.Id_btnAsyncGroupDispatch) .setClickedListener(component -> asyncGroupDispatch()); findComponentById(ResourceTable.Id_btnRevoke) .setClickedListener(component -> revoke()); findComponentById(ResourceTable.Id_btnSyncDispatchBarrier) .setClickedListener(component -> syncDispatchBarrier()); findComponentById(ResourceTable.Id_btnAsyncDispatchBarrier) .setClickedListener(component -> asyncDispatchBarrier()); findComponentById(ResourceTable.Id_btnApplyDispatch) .setClickedListener(component -> applyDispatch()); } ... private void timeConsuming() { for (int i = 0; i < 100000000; ++i); } private void syncDispatch() { TaskDispatcher taskDispatcher = getGlobalTaskDispatcher( TaskPriority.DEFAULT); HiLog.info(label, "任务1即将分发"); taskDispatcher.syncDispatch(new Runnable() { @Override public void run() { HiLog.info(label, "任务1开始执行"); timeConsuming(); HiLog.info(label, "任务1执行完成"); } }); HiLog.info(label, "任务1分发完成"); HiLog.info(label, "任务2即将分发"); taskDispatcher.syncDispatch(new Runnable() { @Override public void run() { HiLog.info(label, "任务2开始执行"); timeConsuming(); HiLog.info(label, "任务2执行完成"); } }); HiLog.info(label, "任务2分发完成"); HiLog.info(label, "任务3即将分发"); taskDispatcher.syncDispatch(new Runnable() { @Override public void run() { HiLog.info(label, "任务3开始执行"); timeConsuming(); HiLog.info(label, "任务3执行完成"); } }); HiLog.info(label, "任务3分发完成"); } private void asyncDispatch() { TaskDispatcher taskDispatcher = getGlobalTaskDispatcher( TaskPriority.DEFAULT); HiLog.info(label, "任务1即将分发"); taskDispatcher.asyncDispatch(new Runnable() { @Override public void run() { HiLog.info(label, "任务1开始执行"); timeConsuming(); HiLog.info(label, "任务1执行完成"); } }); HiLog.info(label, "任务1分发完成"); HiLog.info(label, "任务2即将分发"); taskDispatcher.asyncDispatch(new Runnable() { @Override public void run() { HiLog.info(label, "任务2开始执行"); timeConsuming(); HiLog.info(label, "任务2执行完成"); } }); HiLog.info(label, "任务2分发完成"); HiLog.info(label, "任务3即将分发"); taskDispatcher.asyncDispatch(new Runnable() { @Override public void run() { HiLog.info(label, "任务3开始执行"); timeConsuming(); HiLog.info(label, "任务3执行完成"); } }); HiLog.info(label, "任务3分发完成"); } private void delayDispatch() { TaskDispatcher taskDispatcher = getGlobalTaskDispatcher( TaskPriority.DEFAULT); calendar.setTimeInMillis(System.currentTimeMillis()); HiLog.info(label, "任务即将分发:%{public}s", simpleDateFormat.format(calendar.getTime())); taskDispatcher.delayDispatch(new Runnable() { @Override public void run() { calendar.setTimeInMillis(System.currentTimeMillis()); HiLog.info(label, "任务开始执行:%{public}s", simpleDateFormat.format(calendar.getTime())); timeConsuming(); calendar.setTimeInMillis(System.currentTimeMillis()); HiLog.info(label, "任务执行完成:%{public}s", simpleDateFormat.format(calendar.getTime())); } }, 100); calendar.setTimeInMillis(System.currentTimeMillis()); HiLog.info(label, "任务分发完成:%{public}s", simpleDateFormat.format(calendar.getTime())); } private void asyncGroupDispatch() { TaskDispatcher taskDispatcher = createParallelTaskDispatcher( "PTD1", TaskPriority.DEFAULT); Group group = taskDispatcher.createDispatchGroup(); taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { HiLog.info(label, "任务1开始执行"); timeConsuming(); HiLog.info(label, "任务1执行完成"); } }); taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { HiLog.info(label, "任务2开始执行"); timeConsuming(); HiLog.info(label, "任务2执行完成"); } }); taskDispatcher.groupDispatchNotify(group, new Runnable() { @Override public void run() { HiLog.info(label, "组中任务执行完成"); } }); } private void revoke() { TaskDispatcher taskDispatcher = getGlobalTaskDispatcher( TaskPriority.DEFAULT); HiLog.info(label, "任务即将分发"); Revocable revocable = taskDispatcher.delayDispatch(new Runnable() { @Override public void run() { HiLog.info(label, "任务开始执行"); timeConsuming(); HiLog.info(label, "任务执行完成"); } }, 100); HiLog.info(label, "任务分发完成"); if (revocable.revoke()) HiLog.info(label, "任务取消成功"); else HiLog.info(label, "任务取消失败"); } private void syncDispatchBarrier() { TaskDispatcher taskDispatcher = createParallelTaskDispatcher( "PTD1", TaskPriority.DEFAULT); Group group = taskDispatcher.createDispatchGroup(); taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { HiLog.info(label, "任务1开始执行"); timeConsuming(); HiLog.info(label, "任务1执行完成"); } }); taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { HiLog.info(label, "任务2开始执行"); timeConsuming(); HiLog.info(label, "任务2执行完成"); } }); HiLog.info(label, "屏障任务即将设置"); taskDispatcher.syncDispatchBarrier(new Runnable() { @Override public void run() { HiLog.info(label, "屏障任务开始执行"); timeConsuming(); HiLog.info(label, "屏障任务执行完成"); } }); HiLog.info(label, "屏障任务设置完成"); } private void asyncDispatchBarrier() { TaskDispatcher taskDispatcher = createParallelTaskDispatcher( "PTD1", TaskPriority.DEFAULT); Group group = taskDispatcher.createDispatchGroup(); taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { HiLog.info(label, "任务1开始执行"); timeConsuming(); HiLog.info(label, "任务1执行完成"); } }); taskDispatcher.asyncGroupDispatch(group, new Runnable() { @Override public void run() { HiLog.info(label, "任务2开始执行"); timeConsuming(); HiLog.info(label, "任务2执行完成"); } }); HiLog.info(label, "屏障任务即将设置"); taskDispatcher.asyncDispatchBarrier(new Runnable() { @Override public void run() { HiLog.info(label, "屏障任务开始执行"); timeConsuming(); HiLog.info(label, "屏障任务执行完成"); } }); HiLog.info(label, "屏障任务设置完成"); } private void applyDispatch() { TaskDispatcher taskDispatcher = createParallelTaskDispatcher( "PTD1", TaskPriority.DEFAULT); taskDispatcher.applyDispatch((index) -> { HiLog.info(label, "任务开始执行:%{public}d", index); timeConsuming(); HiLog.info(label, "任务执行完成:%{public}d", index); }, 3); } }
运行效果如下图所示:
EventHandler是一种从一个线程向另一个线程,投递InnerEvent事件或Runnable任务的线程通信机制。
每一个EventHandler都和特定线程的EventRunner绑定,并且该线程内部有一个事件队列。EventHandler可以投递特定的InnerEvent事件或Runnable任务到这个事件队列。
EventRunner从事件队列中循环地取出事件:
一般而言,EventHandler有两个主要作用:
例程:Event
...\Event\entry\src\main\resources\base\graphic\background_button.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:shape="oval"> <solid ohos:color="#00a2e8"/> </shape>
...\Event\entry\src\main\resources\base\layout\ability_main.xml
<?xml version="1.0" encoding="utf-8"?> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:alignment="center" ohos:orientation="vertical" ohos:background_element="#000000"> <Text ohos:id="$+id:txt" ohos:height="match_content" ohos:width="match_content" ohos:text="珍惜时间" ohos:text_size="40fp" ohos:text_color="#ffffff" /> <Button ohos:id="$+id:btn" ohos:height="80vp" ohos:width="80vp" ohos:top_margin="50vp" ohos:background_element="$graphic:background_button" ohos:text="开始" ohos:text_size="26fp" ohos:text_color="#ffffff" /> </DirectionalLayout>
...\Event\entry\src\main\java\com\minwei\event\slice\MainAbilitySlice.java
class ClockEventHandler extends EventHandler { private Text text; public ClockEventHandler(EventRunner eventRunner, Text text) { super(eventRunner); this.text = text; } @Override protected void processEvent(InnerEvent event) { super.processEvent(event); if (event.eventId == 100) text.setText(new SimpleDateFormat("H:mm:ss") .format(event.object)); } } public class MainAbilitySlice extends AbilitySlice { private EventRunner eventRunner; private ClockEventHandler eventHandler; private TaskDispatcher taskDispatcher; private Button button; private boolean stop = false; @Override public void onStart(Intent intent) { ... eventRunner = EventRunner.getMainEventRunner(); eventHandler = new ClockEventHandler(eventRunner, (Text)findComponentById(ResourceTable.Id_txt)); taskDispatcher = createParallelTaskDispatcher( "PTD1", TaskPriority.DEFAULT); button = (Button)findComponentById(ResourceTable.Id_btn); button.setClickedListener(component -> { if (button.getText().equals("开始") || button.getText().equals("继续")) { ((ShapeElement)button .getBackgroundElement()) .setRgbColor(new RgbColor(255, 127, 39)); button.setText("暂停"); stop = false; taskDispatcher.asyncDispatch(new Runnable() { @Override public void run() { while (!stop) { eventHandler.sendEvent(InnerEvent.get( 100, Calendar.getInstance().getTime())); try { Thread.sleep(1000); } catch (InterruptedException exception) {} } } }); } else { ((ShapeElement)button .getBackgroundElement()) .setRgbColor(new RgbColor(34, 177, 76)); button.setText("继续"); stop = true; } }); } ... }
运行效果如下图所示: