1e41f4b71Sopenharmony_ci# Communication Between Threads
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Introduction
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ciDuring application development, some time-consuming tasks are executed in subthreads to prevent the main thread from being blocked, delivering a better user experience. Generally, a subthread can independently complete its task. However, in most cases, data needs to be transferred from the main thread to the subthread, or the task execution result needs to be returned from the subthread to the main thread. Therefore, communication between the main thread and subthread is necessary. This topic describes several example scenarios to show how to implement data communication between the main thread and subthreads in OpenHarmony application development.
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ci## Independent Execution of a Task
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ciIf a time-consuming task can be executed independently by a subthread, the subthread only needs to return the execution result to the main thread after the task is executed. You can perform the following operations to implement this scenario.
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ciFirst, import the TaskPool module.
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ci```typescript
14e41f4b71Sopenharmony_ciimport { taskpool } from '@kit.ArkTS';
15e41f4b71Sopenharmony_ci```
16e41f4b71Sopenharmony_ciThen, implement the task that the subthread needs to perform.
17e41f4b71Sopenharmony_ci```typescript
18e41f4b71Sopenharmony_ci@Concurrent // Methods executed in the task must be decorated by @Concurrent. Otherwise, they cannot be called.
19e41f4b71Sopenharmony_ciexport function loadPicture(count: number): IconItemSource[] {
20e41f4b71Sopenharmony_ci  let iconItemSourceList: IconItemSource[] = [];
21e41f4b71Sopenharmony_ci  // Traverse and add six IconItem data records.
22e41f4b71Sopenharmony_ci  for (let index = 0; index < count; index++) {
23e41f4b71Sopenharmony_ci    const numStart: number = index * 6;
24e41f4b71Sopenharmony_ci    // Six images are used cyclically.
25e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.nearby'), `item${numStart + 1}`));
26e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.scan'), `item${numStart + 2}`));
27e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.shop'), `item${numStart + 3}`));
28e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.cards'), `item${numStart + 4}`));
29e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.album'), `item${numStart + 5}`));
30e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.applet'), `item${numStart + 6}`));
31e41f4b71Sopenharmony_ci  }
32e41f4b71Sopenharmony_ci  return iconItemSourceList;
33e41f4b71Sopenharmony_ci}
34e41f4b71Sopenharmony_ci```
35e41f4b71Sopenharmony_ciFinally, call **execute** in the **TaskPool** class to execute the task.
36e41f4b71Sopenharmony_ci```typescript
37e41f4b71Sopenharmony_ci......
38e41f4b71Sopenharmony_ci// Create a task.
39e41f4b71Sopenharmony_cilet lodePictureTask: taskpool.Task = new taskpool.Task(loadPicture, 30);
40e41f4b71Sopenharmony_ci// Execute the task and return the result.
41e41f4b71Sopenharmony_citaskpool.execute(lodePictureTask).then((res: IconItemSource[]) => {
42e41f4b71Sopenharmony_ci  // Execution result of the loadPicture API.
43e41f4b71Sopenharmony_ci  this.iconItemSourceList = res; 
44e41f4b71Sopenharmony_ci})
45e41f4b71Sopenharmony_ci......
46e41f4b71Sopenharmony_ci```
47e41f4b71Sopenharmony_ci
48e41f4b71Sopenharmony_ci## Simultaneous Execution of Multiple Tasks
49e41f4b71Sopenharmony_ci
50e41f4b71Sopenharmony_ciIf multiple tasks are executed simultaneously, their execution time and result return time vary according to the task complexity. If the main thread requires the execution results of all tasks, you can use the following code snippet:
51e41f4b71Sopenharmony_ci```typescript
52e41f4b71Sopenharmony_ci......
53e41f4b71Sopenharmony_cilet taskGroup: taskpool.TaskGroup = new taskpool.TaskGroup();
54e41f4b71Sopenharmony_citaskGroup.addTask(new taskpool.Task(loadPicture, 30));
55e41f4b71Sopenharmony_citaskGroup.addTask(new taskpool.Task(loadPicture, 20));
56e41f4b71Sopenharmony_citaskGroup.addTask(new taskpool.Task(loadPicture, 10));
57e41f4b71Sopenharmony_citaskpool.execute(taskGroup).then((ret: IconItemSource[][]) => {
58e41f4b71Sopenharmony_ci  for (let i = 0; i < ret.length; i++) {
59e41f4b71Sopenharmony_ci    for (let j = 0; j < ret[i].length; j++) {
60e41f4b71Sopenharmony_ci      this.iconItemSourceList.push(ret[i][j]);
61e41f4b71Sopenharmony_ci    }
62e41f4b71Sopenharmony_ci  }
63e41f4b71Sopenharmony_ci})
64e41f4b71Sopenharmony_ci......
65e41f4b71Sopenharmony_ci```
66e41f4b71Sopenharmony_ciIn this scenario, all the tasks to be executed are placed in a task group. After all the tasks in the task group are executed, the execution result of each task is placed in an array and returned to the main thread. The main thread can obtain all task execution results at a time.
67e41f4b71Sopenharmony_ci
68e41f4b71Sopenharmony_ciIn addition, if a task needs to process a large amount of data (for example, a list contains 10,000 data records), it is time-consuming to process all the data in one task. In this case, you can split the data into multiple sublists, allocate one task for each sublist, and combine the results of all the tasks. This pattern reduces the processing time and improves user experience.
69e41f4b71Sopenharmony_ci
70e41f4b71Sopenharmony_ci## Communication with the Main Thread During Task Execution
71e41f4b71Sopenharmony_ci
72e41f4b71Sopenharmony_ciIf a subthread needs to periodically notify the main thread of the task status and data changes, or needs to return a large amount of data by segment (for example, a large amount of data read from the database), you can perform the following operations:
73e41f4b71Sopenharmony_ci
74e41f4b71Sopenharmony_ciFirst, implement a method to receive messages sent by the task.
75e41f4b71Sopenharmony_ci```typescript
76e41f4b71Sopenharmony_cifunction notice(data: number): void {
77e41f4b71Sopenharmony_ci  console.info("The subthread task has been executed. Total images loaded:", data)
78e41f4b71Sopenharmony_ci}
79e41f4b71Sopenharmony_ci```
80e41f4b71Sopenharmony_ciThen, add **sendData()** to the task to enable the subthread to send messages to the main thread.
81e41f4b71Sopenharmony_ci```typescript
82e41f4b71Sopenharmony_ci// Use sendData to notify the main thread of information in real time.
83e41f4b71Sopenharmony_ci@Concurrent
84e41f4b71Sopenharmony_ciexport function loadPictureSendData(count: number): IconItemSource[] {
85e41f4b71Sopenharmony_ci  let iconItemSourceList: IconItemSource[] = [];
86e41f4b71Sopenharmony_ci  // Traverse and add six IconItem data records.
87e41f4b71Sopenharmony_ci  for (let index = 0; index < count; index++) {
88e41f4b71Sopenharmony_ci    const numStart: number = index * 6;
89e41f4b71Sopenharmony_ci    // Six images are used cyclically.
90e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.nearby'), `item${numStart + 1}`));
91e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.scan'), `item${numStart + 2}`));
92e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.shop'), `item${numStart + 3}`));
93e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.cards'), `item${numStart + 4}`));
94e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.album'), `item${numStart + 5}`));
95e41f4b71Sopenharmony_ci    iconItemSourceList.push(new IconItemSource($r('app.media.applet'), `item${numStart + 6}`));
96e41f4b71Sopenharmony_ci    taskpool.Task.sendData(iconItemSourceList.length);
97e41f4b71Sopenharmony_ci  }
98e41f4b71Sopenharmony_ci  return iconItemSourceList;
99e41f4b71Sopenharmony_ci}
100e41f4b71Sopenharmony_ci```
101e41f4b71Sopenharmony_ciFinally, use **onReceiveData()** to enable the main thread to receive messages.
102e41f4b71Sopenharmony_ci```typescript
103e41f4b71Sopenharmony_ci......
104e41f4b71Sopenharmony_cilet lodePictureTask: taskpool.Task = new taskpool.Task(loadPictureSendData, 30);
105e41f4b71Sopenharmony_ci// Use notice to receive messages sent by the task.
106e41f4b71Sopenharmony_cilodePictureTask.onReceiveData(notice);
107e41f4b71Sopenharmony_citaskpool.execute(lodePictureTask).then((res: IconItemSource[]) => {
108e41f4b71Sopenharmony_ci  this.iconItemSourceList = res;
109e41f4b71Sopenharmony_ci})
110e41f4b71Sopenharmony_ci......
111e41f4b71Sopenharmony_ci```
112e41f4b71Sopenharmony_ciIn this way, the main thread can receive the data sent by the task through **notice()**.
113e41f4b71Sopenharmony_ci
114e41f4b71Sopenharmony_ci## Instant Communication Between the Worker Thread and Main Thread
115e41f4b71Sopenharmony_ci
116e41f4b71Sopenharmony_ciIn ArkTS, Worker provides a limited number of threads that exist for a longer time than TaskPool threads. Multiple tasks may be executed in one [Worker thread](https://docs.openharmony.cn/pages/v4.0/en/application-dev/arkts-utils/worker-introduction.md/), and the execution duration or returned result of each task may be different. The main thread needs to call different methods in the Worker thread according to the actual situation, and the Worker thread needs to return the result to the main thread in time. You can perform the following operations to implement this scenario.
117e41f4b71Sopenharmony_ci
118e41f4b71Sopenharmony_ciFirst, create a Worker thread to execute different tasks based on parameters.
119e41f4b71Sopenharmony_ci```typescript
120e41f4b71Sopenharmony_ciimport { worker, MessageEvents, ThreadWorkerGlobalScope } from '@kit.ArkTS';
121e41f4b71Sopenharmony_ci 
122e41f4b71Sopenharmony_ciconst workerPort: ThreadWorkerGlobalScope = worker.workerPort;
123e41f4b71Sopenharmony_ci// The Worker thread receives messages from the main thread and calls the corresponding method based on the data type.
124e41f4b71Sopenharmony_ciworkerPort.onmessage = (e: MessageEvents): void => {
125e41f4b71Sopenharmony_ci  if (typeof e.data === "string") {
126e41f4b71Sopenharmony_ci    try {
127e41f4b71Sopenharmony_ci      // The method to call does not carry an input parameter.
128e41f4b71Sopenharmony_ci      let res: string = workerPort.callGlobalCallObjectMethod("picData", "setUp", 0) as string;
129e41f4b71Sopenharmony_ci      console.error("worker: ", res);
130e41f4b71Sopenharmony_ci    } catch (error) {
131e41f4b71Sopenharmony_ci      // Exception handling.
132e41f4b71Sopenharmony_ci      console.error("worker: error code is " + error.code + " error message is " + error.message);
133e41f4b71Sopenharmony_ci    }
134e41f4b71Sopenharmony_ci  } else if (e.data instanceof Array) {
135e41f4b71Sopenharmony_ci    // Return the first four data records.
136e41f4b71Sopenharmony_ci    workerPort.postMessage(e.data.slice(0, 4));
137e41f4b71Sopenharmony_ci  }
138e41f4b71Sopenharmony_ci}
139e41f4b71Sopenharmony_ci```
140e41f4b71Sopenharmony_ciThen, create a **Worker** object in the main thread. When the button is touched, **postMessage** is called to send a message to the Worker thread, and **onmessage** of the **Worker** class is used to receive data returned by the Worker thread.
141e41f4b71Sopenharmony_ci```typescript
142e41f4b71Sopenharmony_ciimport { worker, MessageEvents } from '@kit.ArkTS';
143e41f4b71Sopenharmony_ci......
144e41f4b71Sopenharmony_ci@State iconItemSourceList: IconItemSource[] = [];
145e41f4b71Sopenharmony_ci// Create a Worker object.
146e41f4b71Sopenharmony_ciworkerInstance: worker.ThreadWorker = new worker.ThreadWorker("entry/ets/pages/workers/Worker.ts");
147e41f4b71Sopenharmony_ciaboutToAppear() {
148e41f4b71Sopenharmony_ci  // Initialize the Worker object.
149e41f4b71Sopenharmony_ci  this.initWorker();
150e41f4b71Sopenharmony_ci  for (let index = 0; index < 20; index++) {
151e41f4b71Sopenharmony_ci    const numStart: number = index * 6;
152e41f4b71Sopenharmony_ci    // Six images are used cyclically.
153e41f4b71Sopenharmony_ci    this.iconItemSourceList.push(new IconItemSource($r('app.media.nearby'), `item${numStart + 1}`));
154e41f4b71Sopenharmony_ci    this.iconItemSourceList.push(new IconItemSource($r('app.media.scan'), `item${numStart + 2}`));
155e41f4b71Sopenharmony_ci    this.iconItemSourceList.push(new IconItemSource($r('app.media.shop'), `item${numStart + 3}`));
156e41f4b71Sopenharmony_ci    this.iconItemSourceList.push(new IconItemSource($r('app.media.cards'), `item${numStart + 4}`));
157e41f4b71Sopenharmony_ci    this.iconItemSourceList.push(new IconItemSource($r('app.media.album'), `item${numStart + 5}`));
158e41f4b71Sopenharmony_ci    this.iconItemSourceList.push(new IconItemSource($r('app.media.applet'), `item${numStart + 6}`));
159e41f4b71Sopenharmony_ci  }
160e41f4b71Sopenharmony_ci}
161e41f4b71Sopenharmony_ciinitWorker(){
162e41f4b71Sopenharmony_ci  // Use onmessage to receive data returned by the Worker thread.
163e41f4b71Sopenharmony_ci  this.workerInstance.onmessage = (e: MessageEvents): void => {
164e41f4b71Sopenharmony_ci    if (e.data instanceof Array) {
165e41f4b71Sopenharmony_ci      this.iconItemSourceList = e.data;
166e41f4b71Sopenharmony_ci    }
167e41f4b71Sopenharmony_ci }
168e41f4b71Sopenharmony_ci}
169e41f4b71Sopenharmony_ci......
170e41f4b71Sopenharmony_ciButton ('Change the number of images to five', { type: ButtonType.Normal, stateEffect: true }.)
171e41f4b71Sopenharmony_ci  .fontSize(14)
172e41f4b71Sopenharmony_ci  .borderRadius(8)
173e41f4b71Sopenharmony_ci  .backgroundColor('# 317aff')
174e41f4b71Sopenharmony_ci  .width(250)
175e41f4b71Sopenharmony_ci  .height(60)
176e41f4b71Sopenharmony_ci  .margin({
177e41f4b71Sopenharmony_ci    top: 30
178e41f4b71Sopenharmony_ci  })
179e41f4b71Sopenharmony_ci  .onClick(() => {
180e41f4b71Sopenharmony_ci    // Transfer data to the Worker thread.
181e41f4b71Sopenharmony_ci    this.workerInstance.postMessage(this.iconItemSourceList);
182e41f4b71Sopenharmony_ci  })
183e41f4b71Sopenharmony_ci......
184e41f4b71Sopenharmony_ci```
185e41f4b71Sopenharmony_ciIn the sample code, the Worker thread performs two different processing. When the input data is of the string type, it calls **callGlobalCallObjectMethod** to synchronously call the method in the main thread. When the input data is of the array type, it returns the first four data records of the array to the main thread. In this way, instant communication between the main thread and Worker thread can be implemented.
186e41f4b71Sopenharmony_ci
187e41f4b71Sopenharmony_ci## Worker Thread Synchronously Calls a Method of the Main Thread
188e41f4b71Sopenharmony_ci
189e41f4b71Sopenharmony_ciIf the Worker thread needs to call the method that has been implemented in the main thread, you can perform the following operations:
190e41f4b71Sopenharmony_ci
191e41f4b71Sopenharmony_ciFirst, implement the method in the main thread, create a **Worker** object, and register the method on the **Worker** object.
192e41f4b71Sopenharmony_ci```typescript
193e41f4b71Sopenharmony_ciimport { worker } from '@kit.ArkTS';
194e41f4b71Sopenharmony_ci// Create a Worker object.
195e41f4b71Sopenharmony_ciconst workerInstance: worker.ThreadWorker = new worker.ThreadWorker("entry/ets/pages/workers/Worker.ts");
196e41f4b71Sopenharmony_ci 
197e41f4b71Sopenharmony_ciclass PicData {
198e41f4b71Sopenharmony_ci  public iconItemSourceList: IconItemSource[] = [];
199e41f4b71Sopenharmony_ci  
200e41f4b71Sopenharmony_ci  public setUp(): string {
201e41f4b71Sopenharmony_ci    for (let index = 0; index < 20; index++) {
202e41f4b71Sopenharmony_ci      const numStart: number = index * 6;
203e41f4b71Sopenharmony_ci      // Six images are used cyclically.
204e41f4b71Sopenharmony_ci      this.iconItemSourceList.push(new IconItemSource($r('app.media.nearby'), `item${numStart + 1}`));
205e41f4b71Sopenharmony_ci      this.iconItemSourceList.push(new IconItemSource($r('app.media.scan'), `item${numStart + 2}`));
206e41f4b71Sopenharmony_ci      this.iconItemSourceList.push(new IconItemSource($r('app.media.shop'), `item${numStart + 3}`));
207e41f4b71Sopenharmony_ci      this.iconItemSourceList.push(new IconItemSource($r('app.media.cards'), `item${numStart + 4}`));
208e41f4b71Sopenharmony_ci      this.iconItemSourceList.push(new IconItemSource($r('app.media.album'), `item${numStart + 5}`));
209e41f4b71Sopenharmony_ci      this.iconItemSourceList.push(new IconItemSource($r('app.media.applet'), `item${numStart + 6}`));
210e41f4b71Sopenharmony_ci   }
211e41f4b71Sopenharmony_ci   return "setUpIconItemSourceList success!";
212e41f4b71Sopenharmony_ci  }
213e41f4b71Sopenharmony_ci}
214e41f4b71Sopenharmony_ci 
215e41f4b71Sopenharmony_cilet picData = new PicData();
216e41f4b71Sopenharmony_ci// Register the method on the Worker object.
217e41f4b71Sopenharmony_ciworkerInstance.registerGlobalCallObject("picData", picData);
218e41f4b71Sopenharmony_ciworkerInstance.postMessage("run setUp in picData");
219e41f4b71Sopenharmony_ci```
220e41f4b71Sopenharmony_ciThen, use [callGlobalCallObjectMethod](../reference/apis-arkts/js-apis-worker.md#callglobalcallobjectmethod11) of the **Worker** object to call **setUp()** in the main thread.
221e41f4b71Sopenharmony_ci```typescript
222e41f4b71Sopenharmony_ci......
223e41f4b71Sopenharmony_citry {
224e41f4b71Sopenharmony_ci  // The method to call does not carry an input parameter.
225e41f4b71Sopenharmony_ci  let res: string = workerPort.callGlobalCallObjectMethod("picData", "setUp", 0) as string;
226e41f4b71Sopenharmony_ci  console.error("worker: ", res);
227e41f4b71Sopenharmony_ci} catch (error) {
228e41f4b71Sopenharmony_ci  // Exception handling.
229e41f4b71Sopenharmony_ci  console.error("worker: error code is " + error.code + " error message is " + error.message);
230e41f4b71Sopenharmony_ci}
231e41f4b71Sopenharmony_ci......
232e41f4b71Sopenharmony_ci```
233