# Лабораторная работа №1.

**Разработка многопоточного приложения с использованием Java Concurrency согласно варианту задания.**

Необходимо выполнить следующие задачи:

1. Разработать однопоточный вариант алгоритма и замерить время его работы.
2. Разработать параллельный вариант алгоритма с использованием ThreadPoolExecutor и замерить время его работы
3. Разработать параллельный вариант алгоритма с использованием ForkJoinPoll и замерить время его работы.

## Вариант задания

21. Упорядочить столбцы матрицы по убыванию первых элементов.

## Как запустить программу

1. Для начала, необходимо локально создать аналогичную (или собственную) иерархию файлов программы:

Например:

- project_java (название директории/проекта)

  - /src (папка с файлами программы, но необязательна)

    - ForkJoinSorter.java
    - Main.java
    - MatrixUtils.java
    - SingleThreadSorter.java
    - ThreadPoolSorter.java

2. Далее, необходимо скопировать код из каждого файла, расположенного в удалённой ветке на гите, в локальные файлы, находящиеся внутри директории _src_.

3. Внутри директории, где расположены файлы программы (например, _src_), с помощью командной строки скомпилировать программу следующей командой:

> javac Main.java

4. Убедившись, что компиляция прошла успешно (никаких ошибок в процессе компиляции не возникло), запустить программу следующей командой:

> java Main.java <кол-во строк матрицы (целое число)> <кол-во столбцов матрицы (целое число)>

**Внимание:**

Можно скомпилировать программу, указав в качестве доп. параметра выходную директории (то есть папку, куда, в конечном итоге, будет скомпилирована программа). И далее, перейти в эту папку, и оттуда запустить программу:

> javac -d /путь/к/выходной/директории Main.java

> java Main.java <кол-во строк матрицы (целое число)> <кол-во столбцов матрицы (целое число)>

## Инструменты

- **Язык программирования**: Java
- **Пакеты**:
  - `java.util.concurrent` — используется для реализации многопоточности через `ThreadPoolExecutor` и `ForkJoinPool`
- **Среда разработки**: IntelliJ IDEA
- **Версия JDK**: 21
- **Алгоритмы сортировки**:
  - **Однопоточная сортировка** — реализована вручную с использованием сортировки столбцов
  - **ThreadPoolExecutor** — для многопоточной обработки столбцов с использованием пула потоков
  - **ForkJoinPool** — для многопоточной обработки столбцов с использованием рекурсивных задач

## Как работает программа

Программа выполняет сортировку столбцов матрицы по убыванию первых элементов с использованием различных подходов многозадачности:

1. **Однопоточная версия**: сортирует столбцы матрицы с использованием стандартной сортировки.
2. **Параллельная версия с использованием ThreadPoolExecutor**: выполняет сортировку столбцов с использованием пула потоков для ускорения работы.
3. **Параллельная версия с использованием ForkJoinPool**: использует рекурсивное разделение задач для оптимизации работы с большими массивами данных.

Программа генерирует случайную матрицу (с заданным размером), затем выполняет сортировку для каждого из вариантов и замеряет время выполнения каждого из алгоритмов. Результаты выводятся на экран и записываются в файл.

## Тесты

#### Пример №1

##### Входные данные

```
|  60 | 873 |  81 | 801 |  45 | 838 | 231 |
| 583 | 576 | 207 | 148 | 919 | 809 | 130 |
| 574 | 390 |  21 |   4 | 960 | 350 | 930 |
| 103 | 917 | 619 | 731 | 242 |  16 | 587 |
| 528 | 789 | 815 | 800 | 330 | 416 | 141 |
|  19 | 211 | 831 | 598 | 382 | 572 | 212 |
| 365 | 973 | 680 |  41 | 474 | 922 | 750 |
```

##### Выходные данные

```
| 873 | 838 | 801 | 231 |  81 |  60 |  45 |
| 576 | 809 | 148 | 130 | 207 | 583 | 919 |
| 390 | 350 |  4  | 930 |  21 | 574 | 960 |
| 917 |  16 | 731 | 587 | 619 | 103 | 242 |
| 789 | 416 | 800 | 141 | 815 | 528 | 330 |
| 211 | 572 | 598 | 212 | 831 |  19 | 382 |
| 973 | 922 |  41 | 750 | 680 | 365 | 474 |
```

#### Пример №2

##### Входные данные

```
| 549 | 708 |  958 |  340 | 836 | 575 | 748 |
| 235 | 699 |  906 |  895 | 731 | 957 | 936 |
| 776 | 690 |  156 |  377 | 985 | 995 | 995 |
| 906 | 713 |  410 |  559 | 760 | 694 | 158 |
|  16 | 474 |  825 |  784 | 141 |  59 | 443 |
| 447 | 909 |  521 |  406 | 845 |  66 | 229 |
| 582 | 473 |  856 |  439 | 166 | 721 | 676 |
```

##### Выходные данные

```
| 958 | 836 | 748 | 708 | 575 | 549 | 340 |
| 906 | 731 | 936 | 699 | 957 | 235 | 895 |
| 156 | 985 | 995 | 690 | 995 | 776 | 377 |
| 410 | 760 | 158 | 713 | 694 | 906 | 559 |
| 825 | 141 | 443 | 474 |  59 |  16 | 784 |
| 521 | 845 | 229 | 909 |  66 | 447 | 406 |
| 856 | 166 | 676 | 473 | 721 | 582 | 439 |
```

#### Пример №3

##### Входные данные

```
| 901 | 186 |  700 |  766 | 397 | 422 | 762 |
| 575 | 966 |  882 |  884 | 220 | 440 | 201 |
| 850 | 660 |  909 |  964 | 257 | 177 | 800 |
| 977 | 495 |  832 |  426 | 592 | 769 | 170 |
| 994 | 769 |  347 |  784 |  56 | 225 | 643 |
| 739 | 327 |  700 |  714 | 721 | 157 | 404 |
| 240 | 612 |  992 |  855 | 811 | 756 | 230 |
```

##### Выходные данные

```
| 901 | 766 | 762 | 700 | 422 | 397 | 186 |
| 575 | 884 | 201 | 882 | 440 | 220 | 966 |
| 850 | 964 | 800 | 909 | 177 | 257 | 660 |
| 977 | 426 | 170 | 832 | 769 | 592 | 495 |
| 994 | 784 | 643 | 347 | 225 |  56 | 769 |
| 739 | 714 | 404 | 700 | 157 | 721 | 327 |
| 240 | 855 | 230 | 992 | 756 | 811 | 612 |
```

## Результаты работы на матрице 10000 \* 10000

#### Тест №1

```

    Время сортировки (однопоточный режим): 1615 мс
    Время сортировки (ThreadPoolExecutor): 740 мс
    Время сортировки (ForkJoinPool): 1040 мс
```

#### Тест №2

```
    Время сортировки (однопоточный режим): 1789 мс
    Время сортировки (ThreadPoolExecutor): 743 мс
    Время сортировки (ForkJoinPool): 1020 мс
```

#### Тест №3

```
    Время сортировки (однопоточный режим): 1613 мс
    Время сортировки (ThreadPoolExecutor): 696 мс
    Время сортировки (ForkJoinPool): 1068 мс
```

## Вывод

ThreadExecutor показал наименьшее время выполнения, потому что он эффективно распределяет задачи между несколькими потоками, уменьшая время ожидания на обработку каждого столбца матрицы.

В целом использование потоков ускоряет выполнение, так как позволяет параллельно обрабатывать несколько частей данных, в отличие от последовательной обработки без потоков.
