zubkova_sofya_lab_1_is ready

This commit is contained in:
2025-03-14 11:55:31 +04:00
parent 2e06257c82
commit 4b283d8c2b
5 changed files with 230 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
# Лабораторная работа №1
Разработка многопоточного приложения с использованием Java Concurrency согласно варианту задания.
**Необходимо:**
1. Разработать однопоточный вариант алгоритма и замерить время его работы.
2. Разработать параллельный вариант алгоритма с использованием ThreadPoolExecutor и замерить время его работы
3. Разработать параллельный вариант алгоритма с использованием ForkJoinPoll и замерить время его работы.
Массив генерируется до работы всех вариантов алгоритмов. Все три алгоритма обрабатывают три одинаковых массива.
## Вариант 12.
Определить среднее арифметическое элементов матрицы ниже главной
диагонали.
### Запуск лаборатороной работы:
1. Компиляция программы осуществляется с помощью команды:
> javac Main.java
2. Запуск скомпилированного класса:
> java Main
### Использованные технологии:
- Пакет `java.util.concurrent` предоставляет мощные инструменты для работы с многопоточностью и параллельными вычислениями
- `ExecutorService` и `Executors` используются для управления пулами потоков и выполнения задач
- `ThreadPoolExecutor` - в этом подходе используется пул потоков для параллельного вычисления суммы элементов матрицы. Матрица разбивается на части, и каждая часть обрабатывается отдельным потоком.
- `ForkJoinPool` — специализированный пул потоков, предназначенный для выполнения задач, которые могут быть рекурсивно разбиты на более мелкие подзадачи (fork), а затем объединены (join).
### Как работает программа:
1. Происходит генерация массива размером = size в классе `Main.java`
```
public class Main {
public static void main(String[] args) throws InterruptedException, ExecutionException {
int size = 1000; // size matrix
int[][] matrix = generateMatrix(size);
```
Метод для генерации массива:
```
private static int[][] generateMatrix(int size) {
int[][] matrix = new int[size][size];
Random random = new Random();
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
matrix[i][j] = random.nextInt(1000);
}
}
return matrix;
}
```
2. Создание трех копий исходного массива.
3. Происходит обработка массива с помощью однопоточного варианта алгоритма ( класс SingleThreadedAverage).
4. Класс ThreadPoolAverage обрабатывает матрицу с использованием пула потоков создается пул потоков (задается количество потоков = 4), а каждая строка матрицы обрабатывается в отдельном потоке.
5. Класс ForkJoinAverage обрабатывает матрицу с использованием ForkJoinPool и рекурсивного разделения задачи: если блок большой, он разделяется на две части, и каждая часть обрабатывается рекурсивно.
6. Происходит замер времени работы всех алгоритмов в классе `Main.java`:
```
// SingleThreaded algorithm
long startTime = System.nanoTime();
double singleThreadedResult = SingleThreadedAverage.calculate(matrix);
long endTime = System.nanoTime();
System.out.println("Result: " + singleThreadedResult);
System.out.println("Single-threaded time: " + (endTime - startTime) / 1_000_000 + " ms");
// ThreadPoolExecutor algorithm
startTime = System.nanoTime();
double threadPoolResult = ThreadPoolAverage.calculate(matrix, 4);
endTime = System.nanoTime();
System.out.println("ThreadPoolExecutor time: " + (endTime - startTime) / 1_000_000 + " ms");
// ForkJoinPool algorithm
startTime = System.nanoTime();
double forkJoinResult = ForkJoinAverage.calculate(matrix);
endTime = System.nanoTime();
System.out.println("ForkJoinPool time: " + (endTime - startTime) / 1_000_000 + " ms");
```
### Тесты:
- при size = 1000:
Result: 498.8887907907908
Single-threaded time: 4 ms
ThreadPoolExecutor time: 104 ms
ForkJoinPool time: 42 ms
Result: 499.8382882882883
Single-threaded time: 1 ms
ThreadPoolExecutor time: 35 ms
ForkJoinPool time: 15 ms
- при size = 10000:
Result: 499.5273448344835
Single-threaded time: 26 ms
ThreadPoolExecutor time: 42 ms
ForkJoinPool time: 18 ms
## Вывод:
При небольших размерах матрицы лучше использовать однопоточный вариант алгоритма, так как он дает лучший показатель времени. Однако, если размер генерируемой матрицы большой, то нужно использовать ForkJoinPool. А ThreadPoolExecutor - самый медленный.

View File

@@ -0,0 +1,43 @@
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
public class ForkJoinAverage {
private static class AverageTask extends RecursiveTask<Long> {
private final int[][] matrix;
private final int startRow;
private final int endRow;
AverageTask(int[][] matrix, int startRow, int endRow) {
this.matrix = matrix;
this.startRow = startRow;
this.endRow = endRow;
}
@Override
protected Long compute() {
if (endRow - startRow <= 10) {
long sum = 0;
for (int i = startRow; i < endRow; i++) {
for (int j = 0; j < i; j++) {
sum += matrix[i][j];
}
}
return sum;
} else {
int mid = (startRow + endRow) / 2;
AverageTask left = new AverageTask(matrix, startRow, mid);
AverageTask right = new AverageTask(matrix, mid, endRow);
left.fork();
long rightResult = right.compute();
long leftResult = left.join();
return leftResult + rightResult;
}
}
}
public static double calculate(int[][] matrix) {
ForkJoinPool pool = new ForkJoinPool();
long totalSum = pool.invoke(new AverageTask(matrix, 0, matrix.length));
int totalCount = matrix.length * (matrix.length - 1) / 2;
return (double) totalSum / totalCount;
}
}

View File

@@ -0,0 +1,41 @@
import java.util.concurrent.ExecutionException;
import java.util.Random;
public class Main {
public static void main(String[] args) throws InterruptedException, ExecutionException {
int size = 10000; // size matrix
int[][] matrix = generateMatrix(size);
// SingleThreaded algorithm
long startTime = System.nanoTime();
double singleThreadedResult = SingleThreadedAverage.calculate(matrix);
long endTime = System.nanoTime();
System.out.println("Single-threaded result: " + singleThreadedResult);
System.out.println("Single-threaded time: " + (endTime - startTime) / 1_000_000 + " ms");
// ThreadPoolExecutor algorithm
startTime = System.nanoTime();
double threadPoolResult = ThreadPoolAverage.calculate(matrix, 4);
endTime = System.nanoTime();
//System.out.println("ThreadPool result: " + threadPoolResult);
System.out.println("ThreadPoolExecutor time: " + (endTime - startTime) / 1_000_000 + " ms");
// ForkJoinPool algorithm
startTime = System.nanoTime();
double forkJoinResult = ForkJoinAverage.calculate(matrix);
endTime = System.nanoTime();
//System.out.println("ForkJoin result: " + forkJoinResult);
System.out.println("ForkJoinPool time: " + (endTime - startTime) / 1_000_000 + " ms");
}
private static int[][] generateMatrix(int size) {
int[][] matrix = new int[size][size];
Random random = new Random();
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
matrix[i][j] = random.nextInt(1000);
}
}
return matrix;
}
}

View File

@@ -0,0 +1,15 @@
public class SingleThreadedAverage {
public static double calculate(int[][] matrix) {
long sum = 0;
int count = 0;
int size = matrix.length;
for (int i = 0; i < size; i++) {
for (int j = 0; j < i; j++) {
sum += matrix[i][j];
count++;
}
}
return (double) sum / count;
}

View File

@@ -0,0 +1,38 @@
import java.util.concurrent.*;
public class ThreadPoolAverage {
public static double calculate(int[][] matrix, int numThreads) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
int size = matrix.length;
int chunkSize = size / numThreads;
Future<Long>[] futures = new Future[numThreads];
int[] counts = new int[numThreads];
for (int t = 0; t < numThreads; t++) {
final int startRow = t * chunkSize;
final int endRow = (t == numThreads - 1) ? size : startRow + chunkSize;
final int threadIndex = t;
futures[t] = executor.submit(() -> {
long localSum = 0;
int localCount = 0;
for (int i = startRow; i < endRow; i++) {
for (int j = 0; j < i; j++) {
localSum += matrix[i][j];
localCount++;
}
}
counts[threadIndex] = localCount;
return localSum;
});
}
long totalSum = 0;
int totalCount = 0;
for (int t = 0; t < numThreads; t++) {
totalSum += futures[t].get();
totalCount += counts[t];
}
executor.shutdown();
return (double) totalSum / totalCount;
}
}