Лабораторная №1
Разработка многопоточного приложения с использованием Java Concurrency согласно варианту задания.
Необходимо:
- Разработать однопоточный вариант алгоритма и замерить время его работы.
- Разработать параллельный вариант алгоритма с использованием ThreadPoolExecutor и замерить время его работы
- Разработать параллельный вариант алгоритма с использованием ForkJoinPoll и замерить время его работы.
Массив генерируется до работы всех вариантов алгоритмов. Все три алгоритма обрабатывают три одинаковых массива.
Вариант и задание
- Разделить элементы матрицы на среднее арифметическое всех ее элементов.
Описание
Данная программа разработана для сравнения производительности однопоточного и многопоточного подходов к делению элементов матрицы на среднее арифметическое её элементов. Задача состоит из двух основных частей:
- Вычисление среднего арифметического
- Деление элементов матрицы на среднее арифметическое
Эти этапы выполняются с разными вариантами многопоточности, чтобы выявить их влияние на производительность.
Как запустить
javac DividingByAverage.java
java DividingByAverage
Используемые технологии
Программа использует Java Concurrency, включая классы и интерфейсы:
ExecutorServiceThreadPoolExecutorForkJoinPoolRecursiveAction
Что делает программа
- Генерирует матрицу заданного размера, заполненную случайными значениями.
- Вычисляет среднее арифметическое элементов матрицы.
- Делит все элементы матрицы на среднее арифметическое.
- Замеряет время выполнения для однопоточного и двух многопоточных методов.
Результаты тестов
Для матрцы 5000*5000:
Однопоточный алгоритм:
array[100][100] = 15.0
Среднее арифметическое: 50.00305776
array[100][100] = 0.29998165456191894
Время выполнения: 59 мс
Алгоритм с ThreadPoolExecutor:
Среднее арифметическое: 50.00305776
array[100][100] = 0.29998165456191894
Время выполнения: 56 мс
Алгоритм с ForkJoinPool:
Среднее арифметическое: 50.00305776
array[100][100] = 0.29998165456191894
Время выполнения: 66 мс
Для матрцы 10000*10000:
Однопоточный алгоритм:
array[100][100] = 38.0
Среднее арифметическое: 50.00220663
array[100][100] = 0.7599664607041763
Время выполнения: 186 мс
Алгоритм с ThreadPoolExecutor:
Среднее арифметическое: 50.00220663
array[100][100] = 0.7599664607041763
Время выполнения: 140 мс
Алгоритм с ForkJoinPool:
Среднее арифметическое: 50.00220663
array[100][100] = 0.7599664607041763
Время выполнения: 174 мс
Для матрцы 15000*15000:
Однопоточный алгоритм:
array[100][100] = 4.0
Среднее арифметическое: 49.99820225777778
array[100][100] = 0.08000287649097934
Время выполнения: 388 мс
Алгоритм с ThreadPoolExecutor:
Среднее арифметическое: 49.99820225777778
array[100][100] = 0.08000287649097934
Время выполнения: 323 мс
Алгоритм с ForkJoinPool:
Среднее арифметическое: 49.99820225777778
array[100][100] = 0.08000287649097934
Время выполнения: 379 мс
Вывод
Пока матрицы небольших размеров, можно заметить, что многопоточные алгоритмы могут не иметь преимущества по времени выполнения перед однопоточным алгоритмом или даже быть хуже. Это происходит из-за того, что ThreadPool и ForkJoin затрачивают дополнительные ресурсы на создание и поддержание потоков.
По мере роста размеров матрицы, многопоточные алгоритмы показывают большую эффективность, чем однопоточный. Однопоточный алгоритм начинает работать медленнее из-за большого количества элементов. ThreadPool и ForkJoin начинают работать быстрее, так как дополнительные траты на поддержание потоков с лихвой компенсируются эффективностью многопоточного метода решения задачи.