8.9 KiB
Raw Blame History

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

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

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

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

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

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

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

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

Например:

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

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

      • ForkJoinSorter.java
      • Main.java
      • MatrixUtils.java
      • SingleThreadSorter.java
      • ThreadPoolSorter.java
  1. Далее, необходимо скопировать код из каждого файла, расположенного в удалённой ветке на гите, в локальные файлы, находящиеся внутри директории src.

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

javac Main.java

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

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

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