# Лабораторная работа №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 показал наименьшее время выполнения, потому что он эффективно распределяет задачи между несколькими потоками, уменьшая время ожидания на обработку каждого столбца матрицы. В целом использование потоков ускоряет выполнение, так как позволяет параллельно обрабатывать несколько частей данных, в отличие от последовательной обработки без потоков.