[Huawei Developers] muraliameakula:
Introduction

Huawei provides various services for developers to make ease of development and provides best user experience to end users. In this article, we will cover Thread Management with Java in Harmony OS.

Thread is a lightweight process allows a program to operate more efficiently by doing multiple things at the same time. Threads can be used to perform complicated tasks in the background without interrupting the main program.

The system creates a main thread for an application at runtime. The main thread is created or deleted in accordance with the application, so it is regarded as the core thread for an application. All UI-specific operations, such as UI display and update, are running in the main thread. Therefore, the main thread is also called the UI thread. By default, all operations of an application run in the main thread. If there are time-consuming tasks required by the application, such as downloading files and querying the database, you can create other threads to execute such tasks.

When to Use

If an application contains complex service logic, you may need to create multiple threads to execute various tasks, which causes complex interactions between tasks and threads. This may result in more complicated code and higher maintenance cost. To avoid such issues, you can utilize TaskDispatcher to optimize the dispatch of different tasks.

Available APIs

TaskDispatcher is the basic API for Ability instances to dispatch tasks, and it hides the implementation details of the thread where the task is located. TaskDispatcher. By default, tasks running in the UI thread have higher priorities, and tasks without the need of any results to return usually have lower priorities.

We have multiple type of TaskDispatcher major type of task dispatcher are as follows.

1. GlobalTaskDispatcher

The global task dispatcher is obtained by an ability by calling getGlobalTaskDispatcher().

TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);

2. ParallelTaskDispatcher

The parallel task dispatcher is created and returned by an ability by calling createParallelTaskDispatcher().

String dispatcherName = "parallelTaskDispatcher";
TaskDispatcher parallelTaskDispatcher = createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);

3. SerialTaskDispatcher

The serial task dispatcher is created and returned by an ability by calling createSerialTaskDispatcher().

String dispatcherName = "serialTaskDispatcher";
TaskDispatcher serialTaskDispatcher = createSerialTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);

4. SpecTaskDispatcher

The dedicated task dispatcher is dedicated to a specific thread, which currently refers to the UI thread. Tasks in the UI thread are dispatched using the UITaskDispatcher.

TaskDispatcher uiTaskDispatcher = getUITaskDispatcher();

Development Overview

You need to install DevEcho studio IDE and I assume that you have prior knowledge about the Harmony OS and java.

Hardware Requirements

A computer (desktop or laptop) running Windows 10.

A Huawei phone (with the USB cable), which is used for debugging.

Software Requirements

Java JDK installation package.

DevEcho studio installed.

HMS Core (APK) 4.X or later.

Follows the steps.

1. Create Unity Project.

Open DevEcho studio.

Click NEW Project, select a Project Template.

Select ability template and click Next as per below image.

Enter Project and Package Name and click on Finish.

2. Once you have created the project, DevEco Studio will automatically sync it with Gradle files. Find the below image after synchronization is successful.

3. Update Permission and app version in config.json file as per your requirement, otherwise retain the default values.

4. Create New Ability as follows.

5. Development Procedure.

Create new Ability MainAbilitySlice.java

package com.hms.multithread.slice;

import com.hms.multithread.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Text;
import ohos.app.dispatcher.Group;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

public class MainAbilitySlice extends AbilitySlice {
HiLogLabel LABEL_LOG;
final long delayTime = 5L;
Text result;
String resultString;

@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
result = (Text) findComponentById(ResourceTable.Id_result);
Button globalDispatcher = (Button) findComponentById(ResourceTable.Id_global_disp);
Button parallelDispatcher = (Button) findComponentById(ResourceTable.Id_parallel_disp);
Button uiThreadDispatcher = (Button) findComponentById(ResourceTable.Id_ui_thread_disp);
// Set a click event listener for the button.
globalDispatcher.setClickedListener((listener -> present(new GlobleTaskDispatcher(), new Intent())));
parallelDispatcher.setClickedListener(component -> startParallelThread());
uiThreadDispatcher.setClickedListener(component -> startUIThread());

LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
}

private void startParallelThread() {
resultString="// The execution result may be as follows:";
String dispatcherName = "parallelTaskDispatcher";
TaskDispatcher dispatcher = createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);
// Create a task group for group dispatch.
Group group = dispatcher.createDispatchGroup();
// Add a task (task1) to the group and return an instance used to revoke this task.
dispatcher.asyncGroupDispatch(group, () -> {
resultString=resultString+"\n"+"//download task1 is running";
HiLog.info(LABEL_LOG, "download task1 is running");
});
// Add task2 (associated with task1) to the group.
dispatcher.asyncGroupDispatch(group, () -> {
resultString=resultString+"\n"+"//download task1 is running";
HiLog.info(LABEL_LOG, "download task2 is running");
});
// Close the application after executing all tasks in the task group.
dispatcher.groupDispatchNotify(group, () -> {
resultString=resultString+"\n"+"//the close task is running after all tasks in the group are completed";
//result.setText(resultString);
HiLog.info(LABEL_LOG, "the close task is running after all tasks in the group are completed");
//result.setText("Update UI" + resultString);
});
}

private void startUIThread() {

TaskDispatcher uiTaskDispatcher = getUITaskDispatcher();
// Create a task group for group dispatch.'
Group group = uiTaskDispatcher.createDispatchGroup();
uiTaskDispatcher.delayDispatch(() -> result.setText("Hi Lokesh Kumar this is UI Thread"), delayTime);

// Add task2 (associated with task1) to the group.
uiTaskDispatcher.asyncGroupDispatch(group, () -> HiLog.info(LABEL_LOG, "download task2 is running"));
uiTaskDispatcher.asyncGroupDispatch(group, () -> HiLog.info(LABEL_LOG, "download task3 is running"));

// Close the application after executing all tasks in the task group.
uiTaskDispatcher.groupDispatchNotify(group, () -> HiLog.info(LABEL_LOG, "the close task is running after all tasks in the group are completed"));
}

@Override
public void onActive() {
super.onActive();
}

@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
The following snippet shows how to use a GlobalTaskDispatcher to perform a synchronous dispatch:
private void syncDispather() {
TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);
//Group group = globalTaskDispatcher.createDispatchGroup();
stringBuffer=new StringBuffer();
stringBuffer.append("\n");
globalTaskDispatcher.syncDispatch(() -> {
HiLog.info(LABEL_LOG, "sync task1 run");
stringBuffer.append("// sync task1 run");
});
stringBuffer.append("\n");
HiLog.info(LABEL_LOG, "after sync task1");
stringBuffer.append("// after sync task1");
stringBuffer.append("\n");
globalTaskDispatcher.syncDispatch(() -> {
HiLog.info(LABEL_LOG, "sync task2 run");
stringBuffer.append("// sync task2 run");
});
stringBuffer.append("\n");
HiLog.info(LABEL_LOG, "// after sync task2");
stringBuffer.append("// after sync task2");
globalTaskDispatcher.syncDispatch(() ->{
HiLog.info(LABEL_LOG, "sync task3 run");
stringBuffer.append("// sync task3 run");
});
stringBuffer.append("\n");
HiLog.info(LABEL_LOG, "after sync task3");
stringBuffer.append("// after sync task3");
result.setText("Result"+ stringBuffer );
}
The following code snippet shows how to execute a task for multiple times:
private void countDownLeach() {
final int total = 10;
final CountDownLatch latch = new CountDownLatch(total);
final List<Long> indexList = new ArrayList<>(total);
TaskDispatcher dispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);

// Execute the task multiple times, as specified by the parameter total.
dispatcher.applyDispatch((index) -> {
indexList.add(index);
latch.countDown();
}, total);
// Set the task timeout.
try {
latch.await();
} catch (InterruptedException exception) {
HiLog.error(LABEL_LOG, "latch exception");
}
HiLog.info(LABEL_LOG, "list size matches, %{public}b", (total == indexList.size()));
StringBuffer sb=new StringBuffer();
// result.setText("list size matches, %{public}b"+" "+ (total == indexList.size()));
sb.append("Execute the task multiple times as per below").append("\n");
for (Long i: indexList){
sb.append(i+" ");
if(i%4==0)
sb.append("\n");
}
result.setText(String.valueOf(sb));
// The execution result is as follows:
// list size matches, true
}

Create a layout file under 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="top"
ohos:orientation="vertical">

<Text
ohos:id="$+id:text_time"
ohos:height="match_content"
ohos:width="match_content"
ohos:top_margin="200vp"
ohos:background_element="$graphic:background_ability_main"
ohos:layout_alignment="horizontal_center"
ohos:text="$string:mainability_thread_management"
ohos:text_size="36fp"
/>

<Button
ohos:id="$+id:global_disp"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text_size="25fp"
ohos:padding="10vp"
ohos:start_margin="20vp"
ohos:end_margin="20vp"
ohos:top_margin="90vp"
ohos:bottom_margin="20vp"
ohos:background_element="$graphic:background_button"
ohos:text="$string:mainability_globle_thread"/>

<Button
ohos:id="$+id:parallel_disp"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text_size="25fp"
ohos:padding="10vp"
ohos:margin="20vp"
ohos:background_element="$graphic:background_button"
ohos:text="$string:mainability_parallel_thread"/>

<Button
ohos:id="$+id:ui_thread_disp"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text_size="25fp"
ohos:padding="10vp"
ohos:margin="20vp"
ohos:background_element="$graphic:background_button"
ohos:text="$string:mainability_ui_thread"/>

<Text
ohos:id="$+id:result"
ohos:height="match_content"
ohos:width="match_content"
ohos:top_margin="20vp"
ohos:background_element="$graphic:background_ability_main"
ohos:layout_alignment="horizontal_center"
ohos:text="$string:mainability_result"
ohos:text_size="35vp"
/>
</DirectionalLayout>

6. To build apk and run in device, choose Build > Generate Key and CSR Build for Hap(s)\ APP(s) or Build and Run into connected device, follow the steps.

Result

1. Click on UI Thread|SpecTaskDispatcher Button. It’s bound to the main thread of an application and send result back to main thread and update UI as per below screen.

Pros: Its will update result in UI thread.Tasks in the UI thread are dispatched using the UITaskDispatcher.

For example if you want fetch data form server and update in UI then you can use this method.

Cons: If you trying to update UI other than UI thread its will throw “attempt to update UI in non-UI thread” exception

2. Click on Global Task Dispatcher Button. Its will navigate into other screen, then click on respective button you can separate result.

3. Click on Sync Dispach Button the syncDispatch method dispatches a task synchronously and waits for the task execution in the current thread. The current thread remains blocked until the execution result is returned. As per below result.

Pros : The syncDispatch method will execute all task synchronously. The current thread remains blocked until the execution result is returned. All synchronized blocks synchronized on the same object can only have one thread executing inside them at a time.

Cons: If syncDispatch is used incorrectly, a deadlock will occur.

4. Click on delayDispatch button the applyDispatch executes a specified task on multiple times.

Pros: The delayDispatch method asynchronously dispatches a task with delay and proceeds to the next operation immediately. You can delay your task as per your requirement.

For example if you want execute a method A after 10 second of method B then you can use this delayDispatcher and complete your task easily.

Cons: If delayDispatch is used incorrectly, its will block your script or can throw ANR.

pros:- The applyDispatch executes a specified task multiple times. As per your requirement you can use applyDispatch method to execute a task multiple time like as fetching data from list of data from database or server.

Cons:- If applyDispatch is used incorrectly, its will execute your script infinitely and can block your UI and other resources

Tips and Tricks

Always use the latest version of DevEcho Studio.

Use Harmony Device Simulator from HVD section.

Conclusion

In this article, we have learnt Thread Management in Harmony OS. If an application contains complex service logic, you may need to create multiple threads to execute various tasks, which causes intricate interactions between tasks and threads. This may result in more complicated code and higher maintenance cost. To avoid such issues, you can utilize TaskDispatcher to optimize the dispatch of different tasks.

Thanks for reading the article, please do like and comment your queries or suggestions.

References

Harmony OS: https://www.harmonyos.com/en/develop/

Harmony OS Thread Management: https://developer.harmonyos.com/en/docs/documentation/doc-guides/thread-mgmt-overview-0000000000032127

Original Source