## Вариант 25. *[Упорядочить строки матрицы по убыванию наибольших элементов]*

### <span style="color: blue">Как работает программа?</span>
    Для корректного выполнения лабораторной работы, мне пришлось 
    выбирать правильный способ сортировки матрицы, 
    чтобы в дальнейшем внедрить реализацию с использованием ThreadPoolExecutor 
    и ForkJoinPool. Сначала глаз пал на сортировку пузырьком (очень простая реализация), 
    но в дальнейшем пришло осознание того,
    что каждый шаг алгоритма сильно зависит от предыдущего,
    поэтому будет очень сложно разбить задачу на несколько/подзадачи.
    По итогу я выбрал сортировку слиянием, которая отлично подходит.

### <span style="color: blue"> - *Однопоточный режим* </span>
В классе Program происходит генерация матрицы. матрица передается в конструктор класса SingleThread Pool. Запуск алгоритма просходи в методе OperationMatrixSingleThread(). Работает только один поток, что является большим минусом при работе с большой матрицей.
### <span style="color: blue"> - *Многопоточный режим [ThreadPoolExecutor]* </span>
По условию лабораторной работы, все операции происходят с одной матрицей, поэтому клонируем исходную матрицу и также передаем ее в конструктор класса ExecutorThreadPool. Но конструктор также требует параметр, обозначающий максимальное задействованное количество потоков, которое будет находится в пулле. Передаем значение, равное оптимальному значению нашего железа. ThreadPoolExecutor использует пулл потоков, который поочередно берет задачи из очереди задач. *__но как же пополнять очередь задач задачами?__* для этого необходимо исследовать алгоритм и узнать, что стоит разбить на многопоточное выполнение. В моем случае я сделал разбиение массива многопоточно, то есть разбиение будет не в один поток, а в несколько. Выполнение алгоритма данным способом проигрывает однопоточной реализации при маленьком размере матрицы, но существенно опережает на больших размерах.
### <span style="color: blue"> - *Многопоточный режим [ForkJoinPool]* </span>
Также в конструктор передаем исходную матрицу. Выполнение отличается от предыдущего способа. Принцип работы ForkJoinPool в том, что мы задачу разбиваем на множество подзадач, которые выполняются параллельно в разных потоках и результаты выполнения сливаются в один. Основная цель для выполнения моей задачи: __разбить матрицу на части, отсортировать их по строкам и склеить обратно.__

<hr/>

## <span style="color: red">Запуск лабораторной работы </span>
1. Переходи в папку с файлами программы
2. Ищем запускаемый файл
3. javac *.java __[компиляция файлов]__
4. java filename.java __[запуск исполняемого файла]__

<hr/>

## <span style="color: red">Используемые технологии</span>
1. ThreadPoolExecutor **<span style="color: green">[1]</span>** - используется для выполнения независимых задач в пуле потоков. Можно задать количество выделяемых потоков
2. ForkJoinPool **<span style="color: green">[2]</span>** - используется для рекурсивных задач, которые можно разбить на подзадачи

<br/>**<span style="color: green">[1]</span>** Потоки после выполнения ждут новые задачи
<br/>**<span style="color: green">[2]</span>** Потоки не стоят, а воруют задачи у других потоков, если у них нет работы

<br/>**<span style="color: green">[1]</span>** Создается большое количество потоков => больше переключений => больше трата времени
<br/>**<span style="color: green">[2]</span>** Оптимально использует CPU, минимизируя переключение потоков.

<br/>**<span style="color: green">[1]</span>** Обрабатывает независимые задачи без разбиения
<br/>**<span style="color: green">[2]</span>** Разбивает задачи на мелкие части и обрабатывает их параллельно

## Тестирование

### *Тест 1й. Размер матрицы 10 элементов:*
result <span style="color: red">single</span>:
34500 nano sek </br>
result <span style="color: red">threadPool</span>:
188600 nano sek</br>
result <span style="color: red">forkJoin</span>:
1005100 nano sek


### *Тест 2й. Размер матрицы 100 элементов:*
result <span style="color: red">single</span>:
1052400 nano sek</br>
result <span style="color: red">threadPool</span>:
3056600 nano sek</br>
result <span style="color: red">forkJoin</span>:
2552200 nano sek


### *Тест 3й. Размер матрицы 1000 элементов:*
result <span style="color: red">single</span>:
11658600 nano sek</br>
result <span style="color: red">threadPool</span>:
13080700 nano sek</br>
result <span style="color: red">forkJoin</span>:
15294800 nano sek
 

### <span style="color: gray">Заметим, что при маленьком размере матрицы, однопоток работает в разы эффективней</span>

 
### *Тест 4й. Размер матрицы 5000 элементов:*
result <span style="color: red">single</span>:
91840100 nano sek</br>
result <span style="color: red">threadPool</span>:
77622100 nano sek</br>
result <span style="color: red">forkJoin</span>:
60115500 nano sek


### *Тест 5й. Размер матрицы 10000 элементов:*
result <span style="color: red">single</span>:
343642000 nano sek</br>
result <span style="color: red">threadPool</span>:
222304000 nano sek</br>
result <span style="color: red">forkJoin</span>:
144117500 nano sek
