fork join the frame java

fork join the frame java

frame fork join java 7 is introduced in the framework, this framework is introduced primarily to enhance the capability of parallel computation.

There are two main steps join the fork, the fork is a first, a large number of small task into the task, the second is the join, the results of the first task join together, generating the final result. If the first step does not have any return value, join will wait until all the small tasks are completed.

Remember the previous article we talked about the basic structure of the thread pool do?

  1. ExecutorService - ForkJoinPool used to call the task execution.
  2. workerThread - ForkJoinWorkerThread worker, used to perform specific tasks.
  3. task - ForkJoinTask used to define the tasks to be performed.

Below we explain in detail from three aspects fork join framework.

ForkJoinPool

ForkJoinPool is a ExecutorService an implementation that provides a number of convenient methods of management and worker thread pool.

public class ForkJoinPool extends AbstractExecutorService 
复制代码

A work thread can only handle one task, but ForkJoinPool does not have to create a separate thread for each task, it uses a special data structure of double-ended queue to store task. Such a configuration can easily be stolen work (work-stealing).

What is work-stealing it?

By default, work thread out their tasks that are assigned to the queue from the head. If the queue is empty, then the work thread will be removed from the other end of a queue of tasks to perform a task, or removed from the global queue. This design can take advantage of work thread performance, improve concurrency.

The following look at how to create a ForkJoinPool.

The most common method is to use ForkJoinPool.commonPool () to create, commonPool () all ForkJoinTask provides a common default thread pool.

ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
复制代码

Another way is to use a constructor:

ForkJoinPool forkJoinPool = new ForkJoinPool(2);
复制代码

The argument here is parallel level 2 refers to the thread pool will use two processor cores.

ForkJoinWorkerThread

ForkJoinWorkerThread is used ForkJoinPool worker threads.

public class ForkJoinWorkerThread extends Thread
}
复制代码

And general thread is not the same as it defines two variables:

    final ForkJoinPool pool;                // the pool this thread works in
    final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics
复制代码

One is ForkJoinPool the worker thread belongs. Another is to support Queue work-stealing mechanism.

Look what it's run method:

   public void run() {
        if (workQueue.array == null) { // only run once
            Throwable exception = null;
            try {
                onStart();
                pool.runWorker(workQueue);
            } catch (Throwable ex) {
                exception = ex;
            } finally {
                try {
                    onTermination(exception);
                } catch (Throwable ex) {
                    if (exception == null)
                        exception = ex;
                } finally {
                    pool.deregisterWorker(this, exception);
                }
            }
        }
    }
复制代码

Simply talk is removed from the Queue task execution.

ForkJoinTask

ForkJoinTask task type ForkJoinPool running. Normally we would use its two subclasses: RecursiveAction and RecursiveTask.

They define a required compute implemented () method is used to achieve specific business logic. The difference is RecursiveAction only used to perform the task, but RecursiveTask can return a value.

Since the two classes with the Recursive, so concrete realization also related with recursive logic, we give RecursiveAction use to print a string of examples:

public class CustomRecursiveAction extends RecursiveAction {

    private String workload = "";
    private static final int THRESHOLD = 4;

    private static Logger logger =
            Logger.getAnonymousLogger();

    public CustomRecursiveAction(String workload) {
        this.workload = workload;
    }

    @Override
    protected void compute() {
        if (workload.length() > THRESHOLD) {
            ForkJoinTask.invokeAll(createSubtasks());
        } else {
            processing(workload);
        }
    }

    private List<CustomRecursiveAction> createSubtasks() {
        List<CustomRecursiveAction> subtasks = new ArrayList<>();

        String partOne = workload.substring(0, workload.length() / 2);
        String partTwo = workload.substring(workload.length() / 2, workload.length());

        subtasks.add(new CustomRecursiveAction(partOne));
        subtasks.add(new CustomRecursiveAction(partTwo));

        return subtasks;
    }

    private void processing(String work) {
        String result = work.toUpperCase();
        logger.info("This result - (" + result + ") - was processed by "
                + Thread.currentThread().getName());
    }
}
复制代码

The example above uses a bisection print string.

We look at a RecursiveTask example:

public class CustomRecursiveTask extends RecursiveTask<Integer> {
    private int[] arr;

    private static final int THRESHOLD = 20;

    public CustomRecursiveTask(int[] arr) {
        this.arr = arr;
    }

    @Override
    protected Integer compute() {
        if (arr.length > THRESHOLD) {
            return ForkJoinTask.invokeAll(createSubtasks())
                    .stream()
                    .mapToInt(ForkJoinTask::join)
                    .sum();
        } else {
            return processing(arr);
        }
    }

    private Collection<CustomRecursiveTask> createSubtasks() {
        List<CustomRecursiveTask> dividedTasks = new ArrayList<>();
        dividedTasks.add(new CustomRecursiveTask(
                Arrays.copyOfRange(arr, 0, arr.length / 2)));
        dividedTasks.add(new CustomRecursiveTask(
                Arrays.copyOfRange(arr, arr.length / 2, arr.length)));
        return dividedTasks;
    }

    private Integer processing(int[] arr) {
        return Arrays.stream(arr)
                .filter(a -> a > 10 && a < 27)
                .map(a -> a * 10)
                .sum();
    }
}
复制代码

And much like the example above, but here we need to have a return value.

Task submitted in the ForkJoinPool

With the above two tasks, we can submit in ForkJoinPool in:

int[] intArray= {12,12,13,14,15};
        CustomRecursiveTask customRecursiveTask= new CustomRecursiveTask(intArray);

        int result = forkJoinPool.invoke(customRecursiveTask);
        System.out.println(result);
复制代码

In the above example, we used to invoke submit, invoke will wait for the results of the task.

If you do not use invoke, we can also be replaced with fork () and join ():

customRecursiveTask.fork();
        int result2= customRecursiveTask.join();
        System.out.println(result2);
复制代码

fork () is to be submitted to the task pool, but does not trigger the execution, join () you will get the real execution and returns the result.

Examples described herein may reference github.com/ddean2009/l...

Please refer to more tutorials flydean's blog

Guess you like

Origin juejin.im/post/5e7422796fb9a07c9070fcdf