diff --git a/buslaev_roman_lab_1/Main.java b/buslaev_roman_lab_1/Main.java new file mode 100644 index 0000000..f4ee77c --- /dev/null +++ b/buslaev_roman_lab_1/Main.java @@ -0,0 +1,113 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.*; + +import static java.lang.Math.min; + +public class Main { + private static final int ROWS = 10000; + private static final int COLS = 10000; + private static final int THREADS = 4; + + public static final long MaxValue = 1000000; + + public static void main(String[] args) { + long[][] matrix = generateMatrix(ROWS, COLS); + + long start = System.nanoTime(); + long minSingle = findMinSingleThread(matrix); + long end = System.nanoTime(); + System.out.println("Single: Min number - " + minSingle + ", Time: " + (end - start) / 1000000 + " мс"); + + start = System.nanoTime(); + long minThreadPool = findMinThreadPool(matrix); + end = System.nanoTime(); + System.out.println("ThreadPoolExecutor: Min number - " + minThreadPool + ", Time: " + (end - start) / 1000000 + " мс"); + + start = System.nanoTime(); + long minForkJoin = findMinForkJoin(matrix); + end = System.nanoTime(); + System.out.println("ForkJoinPool: Min number - " + minForkJoin + ", Time: " + (end - start) / 1000000 + " мс"); + } + + private static long[][] generateMatrix(int rows, int cols) { + Random rand = new Random(); + long[][] matrix = new long[rows][cols]; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + matrix[i][j] = rand.nextLong(MaxValue); + } + } + return matrix; + } + + private static long findMinSingleThread(long[][] matrix) { + long my_min = matrix[0][0]; + for(int i = 0; i < matrix.length; i++){ + my_min = min(my_min, findMinInRaw(matrix[i])); + } + return my_min; + } + + private static long findMinInRaw(long[] arr){ + long my_min = arr[0]; + for(int i = 1; i < arr.length; i++){ + my_min = min(my_min, arr[i]); + } + return my_min; + } + + private static long findMinThreadPool(long[][] matrix) { + ExecutorService executor = Executors.newFixedThreadPool(THREADS); + List> results = new ArrayList<>(); + + for (long[] row : matrix) { + results.add(executor.submit(() -> findMinInRaw(row))); + } + + long min = MaxValue; + for (Future future : results) { + try { + min = min(min, future.get()); + } catch (Exception e) { + e.printStackTrace(); + } + } + executor.shutdown(); + return min; + } + + private static long findMinForkJoin(long[][] matrix) { + ForkJoinPool pool = new ForkJoinPool(); + return pool.invoke(new MinTask(matrix, 0, matrix.length)); + } + + static class MinTask extends RecursiveTask { + private static final int MAX_ROWS = 1000; + private final long[][] matrix; + private final int startRow, endRow; + + MinTask(long[][] matrix, int startRow, int endRow) { + this.matrix = matrix; + this.startRow = startRow; + this.endRow = endRow; + } + + @Override + protected Long compute() { + if (endRow - startRow <= MAX_ROWS) { + long my_min = Long.MAX_VALUE; + for (int i = startRow; i < endRow; i++) { + my_min = min(my_min, findMinInRaw(matrix[i])); + } + return my_min; + } + int mid = (startRow + endRow) / 2; + MinTask leftTask = new MinTask(matrix, startRow, mid); + MinTask rightTask = new MinTask(matrix, mid, endRow); + invokeAll(leftTask, rightTask); + return min(leftTask.join(), rightTask.join()); + } + } +} diff --git a/buslaev_roman_lab_1/README.md b/buslaev_roman_lab_1/README.md new file mode 100644 index 0000000..dfcf7a2 --- /dev/null +++ b/buslaev_roman_lab_1/README.md @@ -0,0 +1,77 @@ +# Лабораторная работа №1 + +Разработка многопоточного приложения с использованием Java Concurrency. +Мой вариант -> 4) Определить минимальный элемент матрицы. + +## Цель + +Сравнить время выполнения трех реализаций алгоритма поиска минимального элемента в большой матрице: +1. Однопоточный алгоритм. +2. Многопоточный алгоритм с использованием `ThreadPoolExecutor`. +3. Многопоточный алгоритм с использованием `ForkJoinPool`. + +Все три алгоритма обрабатывают один и тот же массив, который генерируется один раз перед запуском. + +--- + +## Описание программы + +1. **Генерация матрицы** + Метод `generateMatrix(...)` создает матрицу размером `ROWS x COLS`, заполняя ее случайными числами, используя `Random.nextLong(MaxValue)`. + +2. **Однопоточный поиск минимума** + - `findMinSingleThread(...)` обходит все строки и для каждой строки вызывает `findMinInRaw(...)` (локальный поиск минимума в одномерном массиве). + - Возвращается общий минимальный элемент по всей матрице. + +3. **Поиск минимума с `ThreadPoolExecutor`** + - `findMinThreadPool(...)` создает пул потоков из `THREADS`. + - Для каждой строки матрицы отправляет задачу (`Callable`), которая в свою очередь вызывает `findMinInRaw(...)` для поиска минимума в одной строке. + - Собираются результаты всех `Future`, ищется минимальный элемент из их значений. + +4. **Поиск минимума с `ForkJoinPool`** + - `findMinForkJoin(...)` создает `ForkJoinPool` и запускает рекурсивную задачу `MinTask`. + - `MinTask` (наследует `RecursiveTask`) делит промежуток строк на две части, пока не достигнет порога `MAX_ROWS`. Когда участок достаточно мал, последовательно ищет минимум по строкам. + - Объединяет (берет минимум) из двух подзадач. + +5. **Замер времени** + - В `main(...)` для каждого из трех алгоритмов замеряется время до и после выполнения (через `System.nanoTime()`). + - Результаты выводятся в консоль. + +--- + +## Как запустить + +1. Установить JDK (Java 8 или выше). +2. Скомпилировать: + ```bash + javac Main.java + ``` +3. Запустить: + ```bash + java Main + ``` +4. По завершении вы увидите три строки с минимальным элементом и временем выполнения (в мс) для: + - Однопоточного алгоритма + - Алгоритма с `ThreadPoolExecutor` + - Алгоритма с `ForkJoinPool` + +--- + +## Пример вывода + +``` +Single: Min number - 0, Time: 107 мс +ThreadPoolExecutor: Min number - 0, Time: 102 мс +ForkJoinPool: Min number - 0, Time: 63 мс +``` + +Числа зависят от размера матрицы и мощности процессора. +Чтобы было более наглядно видно разницу по времени между всеми реализации алгоритма, нужно более большую матрицу. + +--- + +## Вывод +1. **Однопоточный** вариант прост в реализации, но при больших размерах матрицы работает долго. +2. **ThreadPoolExecutor** позволяет распараллелить обработку строк матрицы и значительно ускорить поиск. +3. **ForkJoinPool** часто дает еще более высокое ускорение за счет механизма рекурсивного разбиения задач, но реальная производительность зависит от конфигурации процессоров и параметров разбиения. +