Параллельное Программирование На Java8. Создание Многопоточных Программ С Использованием Fork/Join Framework

Статья посвящена такому интересному и полезному механизму (наборам механизмов и библиотек), как Платформа вилки/соединения .

Он позволяет многократно ускорить вычисления и добиться максимальных результатов обработки, используя все доступные возможности системы (процессоров).

В этой статье будут созданы классы, использующие Платформа вилки/соединения .

Код показывает один из возможных вариантов использования параллельного программирования.

Итак, начнем.

При создании приложений следует максимально разделить части, отвечающие за запуск, настройку и обработку данных.

И этот вариант работы с Fork/Join не является исключением.

В примерах будут использоваться классы Start, Stream, Calc соответственно.



Часть первая – запуск

Для тестирования создадим класс Start, он будет служить «точкой запуска».

Значение timebetweenStartEnd покажет нам временной интервал между началом и окончанием вычислений.

Расчеты подразумевают возведение чисел от 0 до 1 000 000 в степени в двух вариантах в однопоточном и многопоточном режиме.

Класс Start определяет пул потоков ФоркДжоинПул() .

Использование метода вызвать() достигнут результат запуска задачи и ожидания ее завершения.

Значение компонентного значения определено как 1000000. Во вновь созданном экземпляре класса Stream определены исходные данные.

С помощью вызова() мы «переводим» эту задачу на выполнение.

  
  
   

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); } }



Часть вторая.

Настраивать.

Класс потока

Вторая часть механизма представляет собой класс (Stream), отвечающий за настройку многопоточности.

Теперь у нас есть только два таких варианта: первый основан на количестве обрабатываемых значений в одном потоке (далее — «отсечка»), второй — на количестве процессоров (получается методом доступныепроцессоры() ).

Обратите внимание, что в этой статье не будет обсуждаться механизм динамического создания потоков в зависимости от количества процессоров и/или других условий.

Это тема следующей статьи.

Класс использует абстрактный метод вычислить() , отвечающий за запуск вычислений, в нашем случае это выбор опции расчета и запуск вычислений в методе go класса Calc. Использование метода вызватьВсе() Запустим подзадачи.

Из алгоритма понятно, что если у нас больше одного процессора, или значение отсечки (500000) больше/равно полученным частям, то расчет происходит. В примере мы разбиваем forSplit на несколько частей (две) и запускаем две подзадачи.

При изменении значения переменной countLimit или установке значения countProcessors равным единице будет запущена только одна задача обработки данных.



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)); } } }



Часть третья.

Выполнение расчета.

Класс вычислений

Этот класс отвечает за возведение числа в степень.

Часть ниже предназначена для демонстрации и может содержать любые вычисления от перебора коллекций до записи данных в хранилище.



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



Вместо концовки

Этот материал будет полезен тем, кто только начал изучать параллельное программирование.

Здесь показаны основы работы с небольшой частью функционала.

Обращаю внимание читателей, что при небольших расчетах время, затраченное на создание второй подзадачи, может оказаться больше времени, необходимого для завершения расчета.

В следующих статьях мы приблизимся к созданию гибкого функционала по запуску и определению максимально возможных параллельных потоков, а также затронем тему ограничений, связанных с одновременно выполняемыми командами.

Теги: #Параллельное программирование #многопоточность #многопоточное программирование #java8 #fork/join framework #Разработка веб-сайтов #java #OOP

Вместе с данным постом часто просматривают: