場(chǎng)景介紹
如果應(yīng)用的業(yè)務(wù)邏輯比較復(fù)雜,可能需要?jiǎng)?chuàng)建多個(gè)線程來(lái)執(zhí)行多個(gè)任務(wù)。這種情況下,代碼復(fù)雜難以維護(hù),任務(wù)與線程的交互也會(huì)更加繁雜。要解決此問(wèn)題,開(kāi)發(fā)者可以使用“TaskDispatcher”來(lái)分發(fā)不同的任務(wù)。
接口說(shuō)明
TaskDispatcher 是一個(gè)任務(wù)分發(fā)器,它是 Ability 分發(fā)任務(wù)的基本接口,隱藏任務(wù)所在線程的實(shí)現(xiàn)細(xì)節(jié)。
為保證應(yīng)用有更好的響應(yīng)性,我們需要設(shè)計(jì)任務(wù)的優(yōu)先級(jí)。在 UI 線程上運(yùn)行的任務(wù)默認(rèn)以高優(yōu)先級(jí)運(yùn)行,如果某個(gè)任務(wù)無(wú)需等待結(jié)果,則可以用低優(yōu)先級(jí)。
優(yōu)先級(jí) | 詳細(xì)描述 |
---|---|
HIGH | 最高任務(wù)優(yōu)先級(jí),比默認(rèn)優(yōu)先級(jí)、低優(yōu)先級(jí)的任務(wù)有更高的幾率得到執(zhí)行。 |
DEFAULT | 默認(rèn)任務(wù)優(yōu)先級(jí), 比低優(yōu)先級(jí)的任務(wù)有更高的幾率得到執(zhí)行。 |
LOW | 低任務(wù)優(yōu)先級(jí),比高優(yōu)先級(jí)、默認(rèn)優(yōu)先級(jí)的任務(wù)有更低的幾率得到執(zhí)行。 |
TaskDispatcher 具有多種實(shí)現(xiàn),每種實(shí)現(xiàn)對(duì)應(yīng)不同的任務(wù)分發(fā)器。在分發(fā)任務(wù)時(shí)可以指定任務(wù)的優(yōu)先級(jí),由同一個(gè)任務(wù)分發(fā)器分發(fā)出的任務(wù)具有相同的優(yōu)先級(jí)。系統(tǒng)提供的任務(wù)分發(fā)器有 GlobalTaskDispatcher、ParallelTaskDispatcher、SerialTaskDispatcher 、SpecTaskDispatcher。
-
GlobalTaskDispatcher
全局并發(fā)任務(wù)分發(fā)器,由 Ability 執(zhí)行 getGlobalTaskDispatcher()獲取。適用于任務(wù)之間沒(méi)有聯(lián)系的情況。一個(gè)應(yīng)用只有一個(gè) GlobalTaskDispatcher,它在程序結(jié)束時(shí)才被銷毀。
TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);
-
ParallelTaskDispatcher
并發(fā)任務(wù)分發(fā)器,由 Ability 執(zhí)行 createParallelTaskDispatcher() 創(chuàng)建并返回。與 GlobalTaskDispatcher 不同的是,ParallelTaskDispatcher 不具有全局唯一性,可以創(chuàng)建多個(gè)。開(kāi)發(fā)者在創(chuàng)建或銷毀 dispatcher 時(shí),需要持有對(duì)應(yīng)的對(duì)象引用 。
String dispatcherName = "parallelTaskDispatcher";
TaskDispatcher parallelTaskDispatcher = createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);
-
SerialTaskDispatcher
串行任務(wù)分發(fā)器,由 Ability 執(zhí)行 createSerialTaskDispatcher()創(chuàng)建并返回。由該分發(fā)器分發(fā)的所有的任務(wù)都是按順序執(zhí)行,但是執(zhí)行這些任務(wù)的線程并不是固定的。如果要執(zhí)行并行任務(wù),應(yīng)使用 ParallelTaskDispatcher 或者 GlobalTaskDispatcher,而不是創(chuàng)建多個(gè) SerialTaskDispatcher。如果任務(wù)之間沒(méi)有依賴,應(yīng)使用GlobalTaskDispatcher 來(lái)實(shí)現(xiàn)。它的創(chuàng)建和銷毀由開(kāi)發(fā)者自己管理,開(kāi)發(fā)者在使用期間需要持有該對(duì)象引用。
String dispatcherName = "serialTaskDispatcher";
TaskDispatcher serialTaskDispatcher = createSerialTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);
- SpecTaskDispatcher
專有任務(wù)分發(fā)器,綁定到專有線程上的任務(wù)分發(fā)器。目前已有的專有線程是主線程。 UITaskDispatcher 和 MainTaskDispatcher 都屬于 SpecTaskDispatcher。建議使用 UITaskDispatcher。
UITaskDispatcher:綁定到應(yīng)用主線程的專有任務(wù)分發(fā)器, 由 Ability 執(zhí)行 getUITaskDispatcher() 創(chuàng)建并返回。 由該分發(fā)器分發(fā)的所有的任務(wù)都是在主線程上按順序執(zhí)行,它在應(yīng)用程序結(jié)束時(shí)被銷毀。
TaskDispatcher uiTaskDispatcher = getUITaskDispatcher();
MainTaskDispatcher:由 Ability 執(zhí)行 getMainTaskDispatcher() 創(chuàng)建并返回。
TaskDispatcher mainTaskDispatcher= getMainTaskDispatcher()
開(kāi)發(fā)步驟
- syncDispatch
同步派發(fā)任務(wù):派發(fā)任務(wù)并在當(dāng)前線程等待任務(wù)執(zhí)行完成。在返回前,當(dāng)前線程會(huì)被阻塞。
如下代碼示例展示了如何使用 GlobalTaskDispatcher 派發(fā)同步任務(wù):
globalTaskDispatcher.syncDispatch(new Runnable() {
@Override
public void run() {
HiLog.info(label, "sync task1 run");
}
});
HiLog.info(label, "after sync task1");
globalTaskDispatcher.syncDispatch(new Runnable() {
@Override
public void run() {
HiLog.info(label, "sync task2 run");
}
});
HiLog.info(label, "after sync task2");
globalTaskDispatcher.syncDispatch(new Runnable() {
@Override
public void run() {
HiLog.info(label, "sync task3 run");
}
});
HiLog.info(label, "after sync task3");
// 執(zhí)行結(jié)果如下:
// sync task1 run
// after sync task1
// sync task2 run
// after sync task2
// sync task3 run
// after sync task3
說(shuō)明
如果對(duì) syncDispatch 使用不當(dāng), 將會(huì)導(dǎo)致死鎖。如下情形可能導(dǎo)致死鎖發(fā)生:
- 在專有線程上,利用該專有任務(wù)分發(fā)器進(jìn)行 syncDispatch。
- 在被某個(gè)串行任務(wù)分發(fā)器(dispatcher_a)派發(fā)的任務(wù)中,再次利用同一個(gè)串行任務(wù)分發(fā)器(dispatcher_a)對(duì)象派發(fā)任務(wù)。
- 在被某個(gè)串行任務(wù)分發(fā)器(dispatcher_a)派發(fā)的任務(wù)中,經(jīng)過(guò)數(shù)次派發(fā)任務(wù),最終又利用該(dispatcher_a)串行任務(wù)分發(fā)器派發(fā)任務(wù)。例如:dispatcher_a 派發(fā)的任務(wù)使用 dispatcher_b 進(jìn)行任務(wù)的派發(fā),在 dispatcher_b 派發(fā)的任務(wù)中又利用 dispatcher_a 進(jìn)行派發(fā)任務(wù)。
- 串行任務(wù)分發(fā)器(dispatcher_a)派發(fā)的任務(wù)中利用串行任務(wù)分發(fā)器(dispatcher_b)進(jìn)行同步派發(fā)任務(wù),同時(shí) dispatcher_b 派發(fā)的任務(wù)中利用串行任務(wù)分發(fā)器(dispatcher_a)進(jìn)行同步派發(fā)任務(wù)。在特定的線程執(zhí)行順序下將導(dǎo)致死鎖。
- asyncDispatch
異步派發(fā)任務(wù):派發(fā)任務(wù),并立即返回,返回值是一個(gè)可用于取消任務(wù)的接口。
如下代碼示例展示了如何使用 GlobalTaskDispatcher 派發(fā)異步任務(wù):
Revocable revocable = globalTaskDispatcher.asyncDispatch(new Runnable() {
@Override
public void run() {
HiLog.info(label, "async task1 run");
}
});
HiLog.info(label, "after async task1");
// 執(zhí)行結(jié)果可能如下:
// after async task1
// async task1 run
- delayDispatch
異步延遲派發(fā)任務(wù):異步執(zhí)行,函數(shù)立即返回,內(nèi)部會(huì)在延時(shí)指定時(shí)間后將任務(wù)派發(fā)到相應(yīng)隊(duì)列中。延時(shí)時(shí)間參數(shù)僅代表在這段時(shí)間以后任務(wù)分發(fā)器會(huì)將任務(wù)加入到隊(duì)列中,任務(wù)的實(shí)際執(zhí)行時(shí)間可能晚于這個(gè)時(shí)間。具體比這個(gè)數(shù)值晚多久,取決于隊(duì)列及內(nèi)部線程池的繁忙情況。
如下代碼示例展示了如何使用 GlobalTaskDispatcher 延遲派發(fā)任務(wù):
final long callTime = System.currentTimeMillis();
final long delayTime = 50;
Revocable revocable = globalTaskDispatcher.delayDispatch(new Runnable() {
@Override
public void run() {
HiLog.info(label, "delayDispatch task1 run");
final long actualDelayMs = System.currentTimeMillis() - callTime;
HiLog.info(label, "actualDelayTime >= delayTime : %{public}b" + (actualDelayMs >= delayTime));
}
}, delayTime );
HiLog.info(label, "after delayDispatch task1");
// 執(zhí)行結(jié)果可能如下:
// after delayDispatch task1
// delayDispatch task1 run
// actualDelayTime >= delayTime : true
- Group
任務(wù)組:表示一組任務(wù),且該組任務(wù)之間有一定的聯(lián)系,由 TaskDispatcher 執(zhí)行 createDispatchGroup 創(chuàng)建并返回。將任務(wù)加入任務(wù)組,返回一個(gè)用于取消任務(wù)的接口。
如下代碼示例展示了任務(wù)組的使用方式:將一系列相關(guān)聯(lián)的下載任務(wù)放入一個(gè)任務(wù)組,執(zhí)行完下載任務(wù)后關(guān)閉應(yīng)用。
void groupTest(Context context) {
TaskDispatcher dispatcher = context.createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);
// 創(chuàng)建任務(wù)組。
Group group = dispatcher.createDispatchGroup();
// 將任務(wù)1加入任務(wù)組,返回一個(gè)用于取消任務(wù)的接口。
dispatcher.asyncGroupDispatch(group, new Runnable(){
public void run() {
HiLog.info(label, "download task1 is running");
downLoadRes(url1);
}
});
// 將與任務(wù)1相關(guān)聯(lián)的任務(wù)2加入任務(wù)組。
dispatcher.asyncGroupDispatch(group, new Runnable(){
public void run() {
HiLog.info(label, "download task2 is running");
downLoadRes(url2);
}
});
// 在任務(wù)組中的所有任務(wù)執(zhí)行完成后執(zhí)行指定任務(wù)。
dispatcher.groupDispatchNotify(group, new Runnable(){
public void run() {
HiLog.info(label, "the close task is running after all tasks in the group are completed");
closeApp();
}
});
}
?
// 可能的執(zhí)行結(jié)果:
// download task1 is running
// download task2 is running
// the close task is running after all tasks in the group are completed
// 另外一種可能的執(zhí)行結(jié)果:
// download task2 is running
// download task1 is running
// the close task is running after all tasks in the group are completed
- Revocable
取消任務(wù):Revocable 是取消一個(gè)異步任務(wù)的接口。異步任務(wù)包括通過(guò) asyncDispatch、delayDispatch、asyncGroupDispatch 派發(fā)的任務(wù)。如果任務(wù)已經(jīng)在執(zhí)行中或執(zhí)行完成,則會(huì)返回取消失敗。
如下代碼示例展示了如何取消一個(gè)異步延時(shí)任務(wù):
void postTaskAndRevoke(Context context) {
TaskDispatcher dispatcher = context.getUITaskDispatcher();
Revocable revocable = dispatcher.delayDispatch(new Runnable(){
HiLog.info(label, "delay dispatch");
}, 10);
boolean revoked = revocable.revoke();
HiLog.info(label, "%{public}b", revoked);
}
?
// 一種可能的結(jié)果如下 :
// true
- syncDispatchBarrier
同步設(shè)置屏障任務(wù):在任務(wù)組上設(shè)立任務(wù)執(zhí)行屏障,同步等待任務(wù)組中的所有任務(wù)執(zhí)行完成,再執(zhí)行指定任務(wù)。
說(shuō)明
在全局并發(fā)任務(wù)分發(fā)器(GlobalTaskDispatcher)上同步設(shè)置任務(wù)屏障,將不會(huì)起到屏障作用。
如下代碼示例展示了如何同步設(shè)置屏障:
TaskDispatcher dispatcher = context.createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);
// 創(chuàng)建任務(wù)組。
Group group = dispatcher.createDispatchGroup();
// 將任務(wù)加入任務(wù)組,返回一個(gè)用于取消任務(wù)的接口。
dispatcher.asyncGroupDispatch(group, new Runnable(){
public void run() {
HiLog.info(label, "task1 is running"); // 1
}
});
dispatcher.asyncGroupDispatch(group, new Runnable(){
public void run() {
HiLog.info(label, "task2 is running"); // 2
}
});
dispatcher.syncDispatchBarrier(new Runnable() {
public void run() {
HiLog.info(label, "barrier"); // 3
}});
HiLog.info(label, "after syncDispatchBarrier"); // 4
}
?
// 1和2的執(zhí)行順序不定;3和4總是在1和2之后按順序執(zhí)行。
// 可能的執(zhí)行結(jié)果:
// task1 is running
// task2 is running
// barrier
// after syncDispatchBarrier
// 另外一種執(zhí)行結(jié)果:
// task2 is running
// task1 is running
// barrier
// after syncDispatchBarrier
- asyncDispatchBarrier
異步設(shè)置屏障任務(wù):在任務(wù)組上設(shè)立任務(wù)執(zhí)行屏障后直接返回,指定任務(wù)將在任務(wù)組中的所有任務(wù)執(zhí)行完成后再執(zhí)行。
說(shuō)明
在全局并發(fā)任務(wù)分發(fā)器(GlobalTaskDispatcher)上異步設(shè)置任務(wù)屏障,將不會(huì)起到屏障作用。可以使用并發(fā)任務(wù)分發(fā)器(ParallelTaskDispatcher)分離不同的任務(wù)組,達(dá)到微觀并行、宏觀串行的行為。
如下代碼示例展示了如何異步設(shè)置屏障:
TaskDispatcher dispatcher = context.createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);
// 創(chuàng)建任務(wù)組。
Group group = dispatcher.createDispatchGroup();
// 將任務(wù)加入任務(wù)組,返回一個(gè)用于取消任務(wù)的接口。
dispatcher.asyncGroupDispatch(group, new Runnable(){
public void run() {
HiLog.info(label, "task1 is running"); // 1
}
});
dispatcher.asyncGroupDispatch(group, new Runnable(){
public void run() {
HiLog.info(label, "task2 is running"); // 2
}
});
dispatcher.asyncDispatchBarrier(new Runnable() {
public void run() {
HiLog.info(label, "barrier"); // 3
}
});
HiLog.info(label, "after syncDispatchBarrier"); // 4
}
?
// 1和2的執(zhí)行順序不定,但總在3和4之前執(zhí)行;4可能在3之前執(zhí)行
// 可能的執(zhí)行結(jié)果:
// task1 is running
// task2 is running
// after syncDispatchBarrier
// barrier
- applyDispatch
執(zhí)行多次任務(wù):對(duì)指定任務(wù)執(zhí)行多次。
如下代碼示例展示了如何執(zhí)行多次任務(wù):
final int total = 10;
final CountDownLatch latch = new CountDownLatch(total);
final ArrayList indexList = new ArrayList?>(total);
// 執(zhí)行任務(wù) total 次
dispatcher.applyDispatch((index) -> {
indexList.add(index);
latch.countDown();
}, total);
// 設(shè)置任務(wù)超時(shí)
try {
latch.await();
} catch (InterruptedException exception) {
HiLog.info(label, "latch exception");
}
HiLog.info(label, "list size matches, %{public}b", (total == indexList.size()));
// 執(zhí)行結(jié)果:
// list size matches, true
-
線程
+關(guān)注
關(guān)注
0文章
504瀏覽量
19653 -
鴻蒙
+關(guān)注
關(guān)注
57文章
2321瀏覽量
42749 -
HarmonyOS
+關(guān)注
關(guān)注
79文章
1967瀏覽量
30035
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論