📜 ⬆️ ⬇️

Concurrent programming in Java8. Creating multi-threaded programs using the Fork / Join Framework

The article is devoted to such an interesting and useful mechanism (sets of mechanisms and libraries), as the Fork / Join Framework . It allows you to repeatedly accelerate the calculations, to achieve maximum results in processing, using all the available system features (processors).

This article will create classes using the Fork / Join Framework . The code shows one of the possible applications for parallel programming. So, let's begin.

When creating applications, it is necessary to separate the parts responsible for starting, setting and processing data as much as possible. And this option of working with Fork / Join is no exception. The examples will use the classes Start, Stream, Calc, respectively.

Part one - launch


To test create a class Start, it will serve as a "point" launch. The timebetweenStartEnd value will show us the time interval between the start and end of calculations. By calculations we mean the exponentiation of numbers from 0 to 1,000,000 in two versions in single-threaded and multi-threaded mode.
')
In the Start class, the thread pool ForkJoinPool () is defined. Using the invoke () method, the result of starting the task and waiting for its execution was achieved. The componentValue value is set to 1000000. The original data is defined in the newly created instance of the Stream class. With invoke (), we “translate” this task for execution.

import java.util.concurrent.ForkJoinPool; public class Start { public static void main(String[] args) { final int componentValue = 1000000; Long beginT = System.nanoTime(); ForkJoinPool fjp = new ForkJoinPool(); Stream test = new Stream(componentValue,0,componentValue); fjp.invoke(test); Long endT = System.nanoTime(); Long timebetweenStartEnd = endT - beginT; System.out.println("=====time========" +timebetweenStartEnd); } } 

Part two. Customization. Class stream


The second part of the mechanism is a class (Stream), which is responsible for setting up multithreading. Now we have only two such options: the first is by the number of processed values ​​in one thread (hereinafter referred to as the “cutoff”), the second is by the number of processors (obtained using the availableProcessors () method). Please pay attention to readers that this article will not work out a mechanism for dynamic thread creation depending on the number of processors and / or other conditions. This is the topic of the next article.

The abstract compute () method is used in the class, which is responsible for starting the calculations, in our case it is the choice of the calculation option and the start of calculations in the go method of the Calc class. Using the invokeAll () method, we will launch subtasks.

From the algorithm it can be seen that in case we have more than one processor, or the cut-off value (500000) is greater than / equal to the parts received, then the calculation takes place. In the example, we divide forSplit into several parts (two) and run two subtasks. Changing the value of the countLimit variable or setting the countProcessors value to one will start only one data processing task.

 import java.util.concurrent.RecursiveAction; public class Stream extends RecursiveAction { final int countProcessors = Runtime.getRuntime().availableProcessors(); final int countLimit = 500000; int start; int end; int forSplit; Stream(int componentValue,int startNumber, int endNumber) { forSplit = componentValue; start = startNumber; end = endNumber; } protected void compute() { if (countProcessors == 1 || end - start <= countLimit) { System.out.println("=run="); for(int i = start; i <= end; i++) { new Calc().go(i); } } else { int middle = (start + end)/ 2; invokeAll(new Stream(forSplit, 0, middle), new Stream(forSplit, middle+1, end)); } } } 

Part Three Perform a calculation. Calc class


This class is responsible for raising numbers to a power. The following part is intended for demonstration and may contain any calculations from enumerating collections to writing data to the repository.

 public class Calc { public void go(int numberForCalc) { for(int i = 0; i <= numberForCalc; i++) { double pow = Math.pow(numberForCalc,100); } } } 

Instead of ending


This material will be useful to those who have just begun to learn parallel programming. It shows the basics of working with a small part of the functionality. I draw readers' attention to the fact that for small calculations the time taken to create the second subtask may be longer than the execution time of the calculation. In the following articles we will get closer to creating flexible functionality for launching and defining the maximum possible parallel threads, and also touch on the limitations associated with simultaneously executed commands.

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


All Articles