How to synchronize an array handover between two pool threads?

I have a script like this (this is Java pseudo-code):

There is a main thread that:

1) creates an instance of an array of type C:

C[] arr = new C[LARGE]; 

2) creates and sends tasks that are completed (through operations with the Central Committee), arr. to pool P1:

 for (int i = 0; i < populateThreadCount; i++) { p1.submit(new PopulateTask(arr, start, end)) } 

Each task fills a different range of indices in arr, so at this point in time synchronization between threads in pool P1 is not required.

3) the main thread is waiting for the completion of all fill jobs.

4) after filling in arr, the main thread creates and sends tasks that load (the IO-related operations) the contents of arr into the P2 pool:

 for (int i = 0; i < uploadThreadCount; i++) { p2.submit(new UploadTask(arr, start, end); } 

As before, the ranges do not overlap, each thread has its own range, so internal synchronization between threads in the P2 pool is not required.

In the tasks of filling and loading, the ranges are different, since for the processing of each type there is a different number of threads.

Now I think the most efficient way to synchronize it.

Using CopyOnWriteArrayList is not an option, as it can be very large (millions of items).

My initial idea was to briefly synchronize in the fill task after creating an instance of class C, and then also in the load task:

 C[] arr = new C[LARGE]; for (int i = 0; i < populateThreadCount; i++) { p1.submit(new PopulateTask(arr, start, end) { void run() { for (int j = start; j <= end; j++) { ... do some heavy computation ... arr[j] = new C(some_computed_data); synchronized(arr[j]) {} } } }); } for (int i = 0; i < uploadThreadCount; i++) { p2.submit(new UploadTask(arr, start, end) { void run() { for (int j = start; j <= end; j++) { synchronized(arr[j]) { upload(arr[j]); } } } }); } 

but not sure if this is correct, especially if this empty synchronized block is not optimized by javac or JIT. I cannot create instances of class C before starting populated tasks, because for this I need computed data.

Any ideas if this is correct and if not a way to make it better?

+6
source share
1 answer

You do not need to synchronize anything. The performer offers the necessary visibility of memory. In particular, see the Parallel Package Documentation:

  • Actions in the thread before the Runnable submission to the Executor occur before its execution begins. Similarly for Callables passed to ExecutorService.
  • Actions taken by asynchronous computation represented by future events before actions after receiving the result via Future.get () in another thread.

Thus, changes performed by tasks transferred to the first executor happen earlier than the main thread performs after the executor completed their execution (second rule), and what the main thread does with the array occurs before the actions performed by the tasks transferred to the second performer (first rule).

Since the event used to be transitive, tasks transferred to the second executor will see the changes made by tasks transferred to the first.

+2
source

Source: https://habr.com/ru/post/985635/


All Articles