kuznetsov_danila_lab_1 is ready

This commit is contained in:
2025-03-12 17:19:08 +04:00
parent 2e06257c82
commit 4349696766
3 changed files with 382 additions and 0 deletions

38
kuznetsov_danila_lab_1/Lab 1/.gitignore vendored Normal file
View File

@@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

View File

@@ -0,0 +1,163 @@
package ru.kuznec;
import java.util.*;
import java.util.concurrent.*;
public class MatrixMinFinder {
public static void main(String[] args) {
int n = 10000;
int[][] matrix = generateMatrix(n);
System.out.println("Сгенерирована матрица размером " + n + "x" + n);
// Однопоточный вариант
long startTime = System.nanoTime();
int minSingle = findMinSingleThread(matrix);
long duration = System.nanoTime() - startTime;
System.out.printf("Однопоточный вариант: min = %d, время = %.3f мс%n",
minSingle, duration / 1_000_000.0);
// Параллельный вариант с использованием ThreadPoolExecutor
startTime = System.nanoTime();
int minThreadPool = findMinThreadPool(matrix);
duration = System.nanoTime() - startTime;
System.out.printf("ThreadPoolExecutor: min = %d, время = %.3f мс%n",
minThreadPool, duration / 1_000_000.0);
// Параллельный вариант с использованием ForkJoinPool
startTime = System.nanoTime();
int minForkJoin = findMinForkJoin(matrix);
duration = System.nanoTime() - startTime;
System.out.printf("ForkJoinPool: min = %d, время = %.3f мс%n",
minForkJoin, duration / 1_000_000.0);
}
/**
* Генерация квадратной матрицы случайных чисел в диапазоне [-10000; 10000]
*/
private static int[][] generateMatrix(int n) {
int[][] matrix = new int[n][n];
Random random = new Random();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
matrix[i][j] = random.nextInt(20001) - 10000;
}
}
return matrix;
}
/**
* Однопоточный вариант поиска минимума элементов ниже главной диагонали.
* Для каждой строки i, начиная с i=1 (так как в строке 0 нет элементов ниже диагонали),
* перебираются столбцы от 0 до i-1.
*/
public static int findMinSingleThread(int[][] matrix) {
int n = matrix.length;
int min = Integer.MAX_VALUE;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (matrix[i][j] < min) {
min = matrix[i][j];
}
}
}
return min;
}
/**
* Параллельный вариант с использованием ThreadPoolExecutor.
* Матрица делится на блоки строк, для каждого блока создаётся задача.
*/
public static int findMinThreadPool(int[][] matrix) {
int n = matrix.length;
int numThreads = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
List<Future<Integer>> futures = new ArrayList<>();
int blockSize = (n + numThreads - 1) / numThreads;
for (int t = 0; t < numThreads; t++) {
int startRow = t * blockSize;
int endRow = Math.min(n, startRow + blockSize);
Future<Integer> future = executor.submit(() -> {
int localMin = Integer.MAX_VALUE;
for (int i = Math.max(startRow, 1); i < endRow; i++) {
for (int j = 0; j < i; j++) {
if (matrix[i][j] < localMin) {
localMin = matrix[i][j];
}
}
}
return localMin;
});
futures.add(future);
}
int min = Integer.MAX_VALUE;
try {
for (Future<Integer> future : futures) {
int result = future.get();
if (result < min) {
min = result;
}
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executor.shutdown();
return min;
}
/**
* Параллельный вариант с использованием ForkJoinPool.
* Создаётся рекурсивная задача, которая делит диапазон строк, если он превышает порог.
*/
public static int findMinForkJoin(int[][] matrix) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
MatrixMinTask task = new MatrixMinTask(matrix, 1, matrix.length);
int min = forkJoinPool.invoke(task);
forkJoinPool.shutdown();
return min;
}
/**
* Класс задачи для ForkJoinPool.
* Если количество строк в диапазоне меньше порогового значения, производится последовательное вычисление,
* иначе диапазон делится на две части.
*/
static class MatrixMinTask extends RecursiveTask<Integer> {
private static final int THRESHOLD = 5;
private int[][] matrix;
private int startRow;
private int endRow;
public MatrixMinTask(int[][] matrix, int startRow, int endRow) {
this.matrix = matrix;
this.startRow = startRow;
this.endRow = endRow;
}
@Override
protected Integer compute() {
if (endRow - startRow <= THRESHOLD) {
int localMin = Integer.MAX_VALUE;
for (int i = startRow; i < endRow; i++) {
for (int j = 0; j < i; j++) {
if (matrix[i][j] < localMin) {
localMin = matrix[i][j];
}
}
}
return localMin;
} else {
int mid = (startRow + endRow) / 2;
MatrixMinTask leftTask = new MatrixMinTask(matrix, startRow, mid);
MatrixMinTask rightTask = new MatrixMinTask(matrix, mid, endRow);
leftTask.fork();
int rightResult = rightTask.compute();
int leftResult = leftTask.join();
return Math.min(leftResult, rightResult);
}
}
}
}

View File

@@ -0,0 +1,181 @@
# 1 Лабораторная работа
## Задание
Разработка многопоточного приложения с использованием Java Concurrency согласно варианту задания.
**Необходимо:**
1. Разработать однопоточный вариант алгоритма и замерить время его работы.
2. Разработать параллельный вариант алгоритма с использованием `ThreadPoolExecutor` и замерить время его работы.
3. Разработать параллельный вариант алгоритма с использованием `ForkJoinPool` и замерить время его работы.
**Вариант:** "Определить минимальный элемент матрицы ниже главной диагонали"
---
## Подготовка
### Генерация матрицы
```java
private static int[][] generateMatrix(int n) {
int[][] matrix = new int[n][n];
Random random = new Random();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
matrix[i][j] = random.nextInt(20001) - 10000;
}
}
return matrix;
}
```
*Описание:*
Метод получает размер матрицы `n` и создаёт массив размером `n x n`, заполняя его числами от **-10000** до **10000** (так как `random.nextInt(20001)` возвращает значения от 0 до 20000, а затем вычитается 10000).
---
## Пункт 1. Однопоточный вариант
```java
public static int findMinSingleThread(int[][] matrix) {
int n = matrix.length;
int min = Integer.MAX_VALUE;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (matrix[i][j] < min) {
min = matrix[i][j];
}
}
}
return min;
}
```
*Описание:*
Создаётся переменная `min`, инициализированная максимальным значением типа `int`. Далее происходит последовательный проход по элементам матрицы ниже главной диагонали (для строки `i` перебираются столбцы с `0` до `i-1`), и если найден элемент меньше текущего минимума, переменная `min` обновляется.
---
## Пункт 2. Параллельный вариант с использованием ThreadPoolExecutor
```java
public static int findMinThreadPool(int[][] matrix) {
int n = matrix.length;
int numThreads = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
List<Future<Integer>> futures = new ArrayList<>();
int blockSize = (n + numThreads - 1) / numThreads;
for (int t = 0; t < numThreads; t++) {
int startRow = t * blockSize;
int endRow = Math.min(n, startRow + blockSize);
Future<Integer> future = executor.submit(() -> {
int localMin = Integer.MAX_VALUE;
for (int i = Math.max(startRow, 1); i < endRow; i++) {
for (int j = 0; j < i; j++) {
if (matrix[i][j] < localMin) {
localMin = matrix[i][j];
}
}
}
return localMin;
});
futures.add(future);
}
int min = Integer.MAX_VALUE;
try {
for (Future<Integer> future : futures) {
int result = future.get();
if (result < min) {
min = result;
}
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executor.shutdown();
return min;
}
```
*Описание:*
- Получаем число доступных процессоров и сохраняем его в переменную `numThreads`.
- С помощью `Executors.newFixedThreadPool(numThreads)` создаём пул фиксированного размера.
- Рассчитываем размер блока строк:
```java
int blockSize = (n + numThreads - 1) / numThreads;
```
Таким образом, матрица делится на равные (или почти равные) части.
- Для каждого блока определяется диапазон строк от `startRow` до `endRow`. В лямбда-выражении происходит последовательный поиск минимума в этом диапазоне (начиная с `Math.max(startRow, 1)`, чтобы не обрабатывать строку 0).
- Результаты задач собираются в список `futures`, после чего перебираются и вычисляется глобальный минимум.
- После получения результатов пул потоков закрывается через `executor.shutdown()`.
---
## Пункт 3. Параллельный вариант с использованием ForkJoinPool
```java
public static int findMinForkJoin(int[][] matrix) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
MatrixMinTask task = new MatrixMinTask(matrix, 1, matrix.length);
int min = forkJoinPool.invoke(task);
forkJoinPool.shutdown();
return min;
}
static class MatrixMinTask extends RecursiveTask<Integer> {
private static final int THRESHOLD = 100;
private int[][] matrix;
private int startRow;
private int endRow;
public MatrixMinTask(int[][] matrix, int startRow, int endRow) {
this.matrix = matrix;
this.startRow = startRow;
this.endRow = endRow;
}
@Override
protected Integer compute() {
if (endRow - startRow <= THRESHOLD) {
int localMin = Integer.MAX_VALUE;
for (int i = startRow; i < endRow; i++) {
for (int j = 0; j < i; j++) {
if (matrix[i][j] < localMin) {
localMin = matrix[i][j];
}
}
}
return localMin;
} else {
int mid = (startRow + endRow) / 2;
MatrixMinTask leftTask = new MatrixMinTask(matrix, startRow, mid);
MatrixMinTask rightTask = new MatrixMinTask(matrix, mid, endRow);
leftTask.fork();
int rightResult = rightTask.compute();
int leftResult = leftTask.join();
return Math.min(leftResult, rightResult);
}
}
}
```
*Описание:*
- Создаётся экземпляр `ForkJoinPool` для распараллеливания рекурсивных задач.
- Запускается задача `MatrixMinTask`, которая ищет минимум в строках с `startRow = 1` до `matrix.length`.
- В классе `MatrixMinTask` определён порог `THRESHOLD = 100`. Если диапазон строк меньше или равен порогу, задача решается последовательно. В противном случае диапазон делится на две части:
- **Левая задача:** обрабатывает строки от `startRow` до `mid`.
- **Правая задача:** обрабатывает строки от `mid` до `endRow`.
- Для асинхронного выполнения используется метод `fork()` (для левой задачи), а затем с помощью `compute()` и `join()` происходит объединение результатов двух подзадач.
---
## Запуск
Запустить jar можно командой:
```bash
java -jar Lab-1-jar-with-dependencies.jar
```