1. 程式人生 > 其它 >華為Harmony鴻蒙開發筆記十一:執行緒管理

華為Harmony鴻蒙開發筆記十一:執行緒管理

技術標籤:技術文件鴻蒙HarmonyOS執行緒管理

鴻蒙的執行緒是有TaskDispatcher類來分發的,TaskDispatcher有四種GlobalTaskDispatcher、ParallelTaskDispatcher、SerialTaskDispatcher、SpecTaskDispatcher。

建立物件:

    private String parallelName = "parallelTaskDispatcher";
    private String serialName = "serialTaskDispatcher";
    private TaskDispatcher globalTaskDispatcher;//全域性併發任務分發器
    private TaskDispatcher parallelTaskDispatcher;//併發任務分發器
    private TaskDispatcher serialTaskDispatcher;//序列任務分發器
    private TaskDispatcher uiTaskDispatcher;//專有任務分發器
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);

        globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);
        parallelTaskDispatcher = createParallelTaskDispatcher(parallelName, TaskPriority.DEFAULT);
        serialTaskDispatcher = createSerialTaskDispatcher(serialName, TaskPriority.DEFAULT);
        uiTaskDispatcher = getUITaskDispatcher();
    }

測試同步任務程式碼:

    private void testSyncDispatch() {
        globalTaskDispatcher.syncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "sync task1 run");
            }
        });
        HiLog.info(label, "after sync task1");

        parallelTaskDispatcher.syncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "sync task2 run");
            }
        });
        HiLog.info(label, "after sync task2");

        serialTaskDispatcher.syncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "sync task3 run");
            }
        });
        HiLog.info(label, "after sync task3");
        uiTaskDispatcher.syncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "sync task4 run");
            }
        });
        HiLog.info(label, "after sync task4");
    }

輸出日誌:

01-24 09:14:31.488 4741-27498/com.example.dispatcherdemo I 00201/MY_TAG: sync task1 run
01-24 09:14:31.489 4741-4741/com.example.dispatcherdemo I 00201/MY_TAG: after sync task1
01-24 09:14:36.490 4741-27783/com.example.dispatcherdemo I 00201/MY_TAG: sync task2 run
01-24 09:14:36.491 4741-4741/com.example.dispatcherdemo I 00201/MY_TAG: after sync task2
01-24 09:14:41.492 4741-28065/com.example.dispatcherdemo I 00201/MY_TAG: sync task3 run
01-24 09:14:41.492 4741-4741/com.example.dispatcherdemo I 00201/MY_TAG: after sync task3

syncDispatch是派發同步任務,可以看出無論哪種分發器,只要使用syncDispatch來派發任務,都是同步執行的,有點協程的味道。最後一個uiTaskDispatcher沒有執行是因為發生了死鎖,官網說以下情況使用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)進行同步派發任務。在特定的執行緒執行順序下將導致死鎖

測試非同步任務程式碼:

    private void testAsyncDispatch() {
        globalTaskDispatcher.asyncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "async task1 run");
            }
        });
        HiLog.info(label, "after async task1");
        parallelTaskDispatcher.asyncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "sync task2 run");
            }
        });
        HiLog.info(label, "after sync task2");

        serialTaskDispatcher.asyncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "sync task3 run");
            }
        });
        HiLog.info(label, "after sync task3");
        uiTaskDispatcher.asyncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "sync task4 run");
            }
        });
        HiLog.info(label, "after sync task4");
    }

日誌輸出:

01-24 09:24:37.406 9317-9317/com.example.dispatcherdemo I 00201/MY_TAG: after async task1
01-24 09:24:37.407 9317-9317/com.example.dispatcherdemo I 00201/MY_TAG: after sync task2
01-24 09:24:37.407 9317-9317/com.example.dispatcherdemo I 00201/MY_TAG: after sync task3
01-24 09:24:37.408 9317-9317/com.example.dispatcherdemo I 00201/MY_TAG: after sync task4
01-24 09:24:42.407 9317-30393/com.example.dispatcherdemo I 00201/MY_TAG: async task1 run
01-24 09:24:42.407 9317-30394/com.example.dispatcherdemo I 00201/MY_TAG: sync task2 run
01-24 09:24:42.409 9317-9317/com.example.dispatcherdemo I 00201/MY_TAG: sync task4 run
01-24 09:24:42.409 9317-30395/com.example.dispatcherdemo I 00201/MY_TAG: sync task3 run

無論哪種分發器,只要使用了asyncDispatch分發任務,都是非同步執行,既然這樣,為什麼還要給分發器分類呢。

先測試一下Paralle和Serial分發非同步任務

    private void testSerialDispatch() {
        serialTaskDispatcher.asyncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "serialTaskDispatcher sync task1 run");
            }
        });
        HiLog.info(label, "serialTaskDispatcher after sync task1");
        serialTaskDispatcher.asyncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "serialTaskDispatcher sync task2 run");
            }
        });
        HiLog.info(label, "serialTaskDispatcher after sync task2");
    }

    private void testParalleDispatch() {
        parallelTaskDispatcher.asyncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "parallelTaskDispatcher sync task1 run");
            }
        });
        HiLog.info(label, "parallelTaskDispatcher after sync task1");
        parallelTaskDispatcher.asyncDispatch(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "parallelTaskDispatcher sync task2 run");
            }
        });
        HiLog.info(label, "parallelTaskDispatcher after sync task2");
    }

日誌:

01-24 09:36:52.844 15707-15707/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher after sync task1
01-24 09:36:52.845 15707-15707/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher after sync task2
01-24 09:36:53.845 15707-8432/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher sync task2 run
01-24 09:36:57.845 15707-8431/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher sync task1 run
01-24 09:37:00.949 15707-15707/com.example.dispatcherdemo I 00201/MY_TAG: serialTaskDispatcher after sync task1
01-24 09:37:00.950 15707-15707/com.example.dispatcherdemo I 00201/MY_TAG: serialTaskDispatcher after sync task2
01-24 09:37:05.950 15707-8894/com.example.dispatcherdemo I 00201/MY_TAG: serialTaskDispatcher sync task1 run
01-24 09:37:06.951 15707-9210/com.example.dispatcherdemo I 00201/MY_TAG: serialTaskDispatcher sync task2 run

原來,使用使用syncDispatch和asyncDispatch分發任務,同步非同步是針對於主執行緒的,而ParallelTaskDispatcher、SerialTaskDispatcher的區別是自己派發出去的任務是序列還是並行。

常規操作延時執行:

    private void testDelayDispatch() {
        globalTaskDispatcher.delayDispatch(new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "delayDispatch task1 run");
            }
        }, 50000);
        HiLog.info(label, "after delayDispatch task1");
    }

鴻蒙還可以將執行緒分組,將幾個執行緒放在一個group中,並且可以新增這一組執行緒執行完的回撥:

    private void testGroupDispatch() {
        // 建立任務組。
        Group group = parallelTaskDispatcher.createDispatchGroup();
        // 將任務1加入任務組,返回一個用於取消任務的介面。
        parallelTaskDispatcher.asyncGroupDispatch(group, new Runnable(){
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "download task1 is running");
            }
        });
        // 將與任務1相關聯的任務2加入任務組。
        parallelTaskDispatcher.asyncGroupDispatch(group, new Runnable(){
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "download task2 is running");
            }
        });
        // 在任務組中的所有任務執行完成後執行指定任務。
        parallelTaskDispatcher.groupDispatchNotify(group, new Runnable(){
            @Override
            public void run() {
                HiLog.info(label, "the close task is running after all tasks in the group are completed");
            }
        });
    }

日誌:

01-24 09:49:25.346 4247-8522/com.example.dispatcherdemo I 00201/MY_TAG: download task1 is running
01-24 09:49:25.348 4247-8523/com.example.dispatcherdemo I 00201/MY_TAG: download task2 is running
01-24 09:49:25.349 4247-8587/com.example.dispatcherdemo I 00201/MY_TAG: the close task is running after all tasks in the group are completed

對於分組任務還可以設定屏障任務:可以使用asyncDispatchBarrier和syncDispatchBarrier來派發非同步或同步的屏障執行緒,這種執行緒必須是在Group執行緒執行完成後,才執行的

    private void testBarrierDispatch() {
        // 建立任務組。
        Group group = parallelTaskDispatcher.createDispatchGroup();
        // 將任務加入任務組,返回一個用於取消任務的介面。
        parallelTaskDispatcher.asyncGroupDispatch(group, new Runnable(){
            @Override
            public void run() {
                HiLog.info(label, "parallelTaskDispatcher task1 is running");  // 1
            }
        });
        parallelTaskDispatcher.asyncGroupDispatch(group, new Runnable(){
            @Override
            public void run() {
                HiLog.info(label, "parallelTaskDispatcher task2 is running");  // 2
            }
        });

        parallelTaskDispatcher.syncDispatchBarrier(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "parallelTaskDispatcher barrier is running");  // 3
            }
        });
        HiLog.info(label, "parallelTaskDispatcher after syncDispatchBarrier");  // 4

        TaskDispatcher parallelTaskDispatcher2 = createParallelTaskDispatcher("dispatcherName", TaskPriority.DEFAULT);
        // 建立任務組。
        Group group2 = parallelTaskDispatcher2.createDispatchGroup();
        // 將任務加入任務組,返回一個用於取消任務的介面。
        parallelTaskDispatcher2.asyncGroupDispatch(group2, new Runnable(){
            @Override
            public void run() {
                HiLog.info(label, "parallelTaskDispatcher2 task1 is running");  // 1
            }
        });
        parallelTaskDispatcher2.asyncGroupDispatch(group2, new Runnable(){
            @Override
            public void run() {
                HiLog.info(label, "parallelTaskDispatcher2 task2 is running");  // 2
            }
        });

        parallelTaskDispatcher2.asyncDispatchBarrier(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                HiLog.info(label, "parallelTaskDispatcher2 barrier is running");  // 3
            }
        });
        HiLog.info(label, "parallelTaskDispatcher2 after asyncDispatchBarrier");  // 4
    }
日誌:
01-24 10:08:15.493 30657-9662/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher task1 is running
01-24 10:08:15.493 30657-9663/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher task2 is running
01-24 10:08:16.494 30657-9664/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher barrier is running
01-24 10:08:16.495 30657-30657/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher after syncDispatchBarrier
01-24 10:08:16.496 30657-9727/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher2 task1 is running
01-24 10:08:16.496 30657-30657/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher2 after asyncDispatchBarrier
01-24 10:08:16.496 30657-9728/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher2 task2 is running
01-24 10:08:17.497 30657-9729/com.example.dispatcherdemo I 00201/MY_TAG: parallelTaskDispatcher2 barrier is running

取消任務:Revocable是取消一個非同步任務的介面。非同步任務包括通過 asyncDispatch、delayDispatch、asyncGroupDispatch 派發的任務。如果任務已經在執行中或執行完成,則會返回取消失敗。

    private void testRevocableDispatch() {
        Revocable revocable = parallelTaskDispatcher.delayDispatch(new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "delay dispatch");
            }
        }, 1000);
        boolean revoked = revocable.revoke();
        HiLog.info(label, "%{public}b", revoked);
    }
日誌:
01-24 09:53:45.649 7590-7590/com.example.dispatcherdemo I 00201/MY_TAG: true

執行多次任務:對指定任務執行多次,使用applyDispatch配合CountDownLatch使用,可以讓執行緒重複執行指定次數:

    final int total = 10;
    final CountDownLatch latch = new CountDownLatch(total);
    final ArrayList<Long> indexList = new ArrayList<>(total);
    private void testApplyDispatch() {
        // 執行任務 total 次
        globalTaskDispatcher.applyDispatch((index) -> {
            indexList.add(index);
            HiLog.info(label, "applyDispatch index="+index);
            latch.countDown();
        }, total);

        // 設定任務超時
        try {
            latch.await();
        } catch (InterruptedException exception) {
            HiLog.info(label, "latch exception");
        }
        HiLog.info(label, "list size matches, %{public}b", (total == indexList.size()));
    }
日誌:
01-24 10:16:31.939 29071-7870/com.example.dispatcherdemo I 00201/MY_TAG: applyDispatch index=0
01-24 10:16:31.940 29071-7871/com.example.dispatcherdemo I 00201/MY_TAG: applyDispatch index=1
01-24 10:16:31.940 29071-7873/com.example.dispatcherdemo I 00201/MY_TAG: applyDispatch index=3
01-24 10:16:31.941 29071-7874/com.example.dispatcherdemo I 00201/MY_TAG: applyDispatch index=4
01-24 10:16:31.941 29071-7875/com.example.dispatcherdemo I 00201/MY_TAG: applyDispatch index=5
01-24 10:16:31.941 29071-7872/com.example.dispatcherdemo I 00201/MY_TAG: applyDispatch index=2
01-24 10:16:31.942 29071-7877/com.example.dispatcherdemo I 00201/MY_TAG: applyDispatch index=7
01-24 10:16:31.943 29071-7878/com.example.dispatcherdemo I 00201/MY_TAG: applyDispatch index=8
01-24 10:16:31.943 29071-7879/com.example.dispatcherdemo I 00201/MY_TAG: applyDispatch index=9
01-24 10:16:31.943 29071-7876/com.example.dispatcherdemo I 00201/MY_TAG: applyDispatch index=6
01-24 10:16:31.943 29071-29071/com.example.dispatcherdemo I 00201/MY_TAG: list size matches, true