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
-
sort class Service.SingleThreadSortingStrategy took 3077,43400
sort class Service.MultiThreadSortingStrategy took 352,02520
sort class Service.ForkJoinPoolSort took 309,22610
true
true -
sort class Service.SingleThreadSortingStrategy took 1543,75580
sort class Service.MultiThreadSortingStrategy took 341,52910
sort class Service.ForkJoinPoolSort took 334,00370
true
true -
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 позволяет значительно повысить производительность приложений, особенно на многоядерных системах, без усложнения кода низкоуровневым управлением потоками.