Fork/Join framework of JUC

Divide and conquer framework Fork/Join:

"Divide and Conquer" has always been a very efficient way of dealing with large amounts of data. Simply put, if you want to process 1000 data, but you do not have the ability to process 1000 data, then you can only process 100 of them, and then process 10 times in stages, and combine the results of 10 times. That is the final desired result of processing the original 1000 data.

Fork means to decompose. In the Linux platform, the function fork is used to create a child process, so that the system process can have one more execution branch.

Join means to wait. After using fork(), the system has one more execution branch (thread), so it is necessary to wait for the execution of this execution branch to complete before the final result can be obtained.

The overall structure of data processing using Fork/Join is as follows:

 

Fork/Join execution logic

 

ForkJoinPool has an important interface:

public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
    if (task == null)
        throw new NullPointerException();
    externalPush(task);
    return task;
}

This interface is used as a ForkJoinPool thread pool to submit a ForkJoinTask task. The ForkJoinTask task is a task that supports fork() decomposition and join() waiting. Looking at the abstract class ForkJoinTask, there are two subclasses, RecursiveTask and RecursiveAction, which represent tasks with return values ​​and tasks without return values, respectively. As shown below:

RecursiveTask and RecursiveAction

Below: The use of the Fork/Join framework is shown with the code that calculates the sum of the series.

@ Slf4j
public class ForkJoinTaskExample extends RecursiveTask<Integer> {

    public static final int threshold = 2;
    private int start;
    private int end;

    public ForkJoinTaskExample(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        int sum = 0;

        // Calculate the task if the task is small enough
        boolean canCompute = (end - start) <= threshold;
        if (canCompute) {
            for (int i = start; i <= end; i++) {
                sum += i;
            }
        } else {
            // If the task is greater than the threshold, split into two sub-tasks for calculation
            int middle = (start + end) / 2;
            ForkJoinTaskExample leftTask = new ForkJoinTaskExample(start, middle);
            ForkJoinTaskExample rightTask = new ForkJoinTaskExample(middle + 1, end);

            // execute subtask
            leftTask.fork();
            rightTask.fork();

            // Wait for the task to finish and merge its results
            int leftResult = leftTask.join();
            int rightResult = rightTask.join();

            // merge subtasks
            sum = leftResult + rightResult;
        }
        return sum;
    }

    public static void main(String[] args) {
        ForkJoinPool forkjoinPool = new ForkJoinPool();

        //Generate a calculation task, calculate 1+2+3+4
        ForkJoinTaskExample task = new ForkJoinTaskExample(1, 100);

        // execute the task
        Future<Integer> result = forkjoinPool.submit(task);

        try {
            log.info("result:{}", result.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace ();
        }
    }

}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325072420&siteId=291194637
Recommended