forked from sevastyan_b/SSPR_25
kuznetsov_danila_lab_1 is ready
This commit is contained in:
38
kuznetsov_danila_lab_1/Lab 1/.gitignore
vendored
Normal file
38
kuznetsov_danila_lab_1/Lab 1/.gitignore
vendored
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
181
kuznetsov_danila_lab_1/README.md
Normal file
181
kuznetsov_danila_lab_1/README.md
Normal 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
|
||||
```
|
||||
Reference in New Issue
Block a user