Files



First lab work

Local setup

git clone https://git.is.ulstu.ru/sevastyan_b/SSPR_25.git
cd tukhtarov_ilnur_lab_1

Technologies used

  • java (programming language)
    • java.util.concurrent

Project structure

|   Main.java
|
+---Model
|       Matrix.java
|
+---Repo
|       MatrixRepo.java
|       SortingStrategyRepo.java
|
+---Service
|       ForkJoinPoolSort.java
|       MultiThreadSortingStrategy.java
|       SingleThreadSortingStrategy.java
|
\---utils
        MatrixSortingApp.java

Code explanation

В данном проекте реализованы три стратегии сортировки матрицы с использованием различных подходов к многопоточности из пакета java.util.concurrent.
SingleThreadSortingStrategy
Создание пула с одним потоком выполнения для обработки задачи сортировки.

ExecutorService executorService = Executors.newSingleThreadExecutor();

Отправка задачи сортировки на выполнение в отдельном потоке. Future позволяет контролировать выполнение задачи.

Future<?> sortFuture = executorService.submit(() -> { ... });

Блокирующий вызов для ожидания завершения сортировки.

sortFuture.get();

Корректное завершение работы пула потоков после выполнения задачи.

executorService.shutdown();

MultiThreadSortingStrategy Создание пула с количеством потоков, равным числу доступных процессоров.

int threadCount = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(threadCount);

Использование CountDownLatch для синхронизации завершения первой фазы - нахождения минимальных значений.

CountDownLatch initLatch = new CountDownLatch(threadCount);

Атомарный счетчик для распределения работы между потоками без конфликтов.

AtomicInteger currentColumn = new AtomicInteger(0);

Блокировка доступа к матрице для предотвращения состояния гонки при обмене столбцов.

synchronized (matrix) { ... }

ForkJoinPoolSort Создание пула ForkJoin для эффективного выполнения рекурсивных задач.

private final ForkJoinPool pool = new ForkJoinPool();

Запуск задачи в пуле ForkJoin с ожиданием её завершения.

pool.invoke(new MinCalculationTask(matrix, minValues, 0, matrix.length));

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

private static class MinCalculationTask extends RecursiveAction { ... }

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

invokeAll(
    new MinCalculationTask(matrix, minValues, start, mid),
    new MinCalculationTask(matrix, minValues, mid, end)
);

Modules

Services

  • ForkJoinPoolSort.java - выполняет сортировку ForkJoinPool. Использует RecursiveAction.
  • MultiThreadSortingStrategy.java - выполняет сортировку MultiThread. Использует ExecutorsService.
  • SingleThreadSortingStrategy.java - выполняет сортировку SingleThread. ExecutorService.

Utils

  • MatrixSortingApp.java - вспомогательный класс, отвечающий за создание матрицы, её отображение и замеры в тестах.

Tests

Время выполнения тестов на размере матрицы 10_000

  1. sort class Service.SingleThreadSortingStrategy took 3077,43400
    sort class Service.MultiThreadSortingStrategy took 352,02520
    sort class Service.ForkJoinPoolSort took 309,22610
    true
    true

  2. sort class Service.SingleThreadSortingStrategy took 1543,75580
    sort class Service.MultiThreadSortingStrategy took 341,52910
    sort class Service.ForkJoinPoolSort took 334,00370
    true
    true

  3. sort class Service.SingleThreadSortingStrategy took 1609,73710
    sort class Service.MultiThreadSortingStrategy took 347,30390
    sort class Service.ForkJoinPoolSort took 330,91160
    true
    true

Conclustion

В данной работе продемонстрированы различные подходы к многопоточной обработке данных в Java:

  • Одиночный поток ExecutorService - простое решение для выполнения задачи в фоновом режиме.
  • Многопоточная обработка с ExecutorService - эффективное использование нескольких потоков с синхронизацией через CountDownLatch и AtomicInteger.
  • Fork/Join Framework - современный подход для параллельной обработки с автоматическим разделением задач.

Каждый подход имеет свои преимущества и может быть оптимальным в зависимости от размера задачи и доступных вычислительных ресурсов. Использование современных многопоточных примитивов из пакета java.util.concurrent позволяет значительно повысить производительность приложений, особенно на многоядерных системах, без усложнения кода низкоуровневым управлением потоками.