Многопоточность. Что дальше?
Дорогу осилит идущийСегодня мы завершаем знакомство с многопоточностью и конкурентностью в Java.
Этот раздел позволил нам разобраться с основными принципами разработки в многопоточной среде и продемонстрировал ряд инструментов, от низкоуровневых (по меркам Java) и императивных до высокоуровневых и даже декларативных (как CompletableFuture и, отчасти, пулы потоков).
Если вы освоили данный раздел в рамках курса и более-менее представляете особенности работы и API для каждого из изученных инструментов – поздравляю, вероятно, в рамках многопоточности вы имеете больший базис, чем средний middle-разработчик на СНГ-рынке.
Однако навыки разработчику дает практика. Поэтому даже полученный базис придется закреплять годами, разрабатывая решения для многопоточной среды, обнаруживая и исправляя ошибки, как свои, так и чужие. Но это все приходит со временем, этот навык проблематично получить без практики, особенно, практики на реальных проектах, где руки скованны требованиями к продукту, особенностями реализации и временем, которое допустимо потратить на исправление проблемы.
В рамках данной статью хочется, все же, подсветить вектор развития для тех, кого увлекла тема многопоточности и тех, кто хочет погружаться в нее глубже уже сейчас, а не через годы опыта и километры просмотренных логов.
Что изучать дальше?
В первую очередь, я бы рекомендовал обратить внимание на то, что уже было так или иначе затронуто:
· CompletableFuture. Это мощнейший инструмент, который можно использовать для самых разнообразных задач, оставляя решение стройным и лаконичным за счет функционального стиля. При этом оно, с большего, позволяет уйти от прямого управления потоками. По сути, если ExecutorService дает надстройку, избавляющую от необходимости управлять потоками напрямую, то CompletableFuture дает надстройку над самым сложным из пулов – ForkJoinPool, позволяя уйти от императивного управления задачами в рамках пула, абстрагируясь от fork(), invoke() и join();
· Механизмы синхронизации. Мы изучили многие из них. Но часть оказалась освещена очень поверхностно – полагаю, в голове мало что отложилось о Phaser и StampedLock. В рамках раздела я старался соблюдать баланс между Java и знакомством с концепциями и принципы, которые реализуют конкретные изучаемые классы. Так, я не видел большого смысла вдаваться в особенности вышеназванных классов. Тем более, они не так часто востребованы на практике. Однако к ним стоит вернуться, если тема интересна;
· И снова механизмы синхронизации. Мы изучили (или познакомились) с большинство синхронизаторов, предоставляемых java.util.concurrent, но не со всеми. Оставшиеся не являются чем-то сложным – скорее, я не видел в них чего-то, что нельзя оставить на потом или отдать на самообучение. В данном случае я говорю о классах CountDownLatch и Exchanger;
· Инструменты в рамках java.lang. По сути, мы познакомились только с Thread и методами Object. Да, многие вещи, вроде ThreadGroup не слишком востребованы. Но есть и те, с которыми стоит познакомиться. Хотя бы потому что они используются другими высокоуровневыми механизмами и без понимания основ такие механизмы превращаются в магию из коробки. В качестве примера (и, возможно, пункта для изучения) – ThreadLocal. Сомневаюсь, что вы будете использовать его напрямую, но именно на него завязан, например, SecurityContext, предоставляемый в рамках Spring Security (для тех, кто уже начал знакомство с Spring Framework).
Кроме того, остаются и более глобальные темы, которые не были затронуты или были затронуты вскользь:
· JMM. При знакомстве с volatile, мы уже встречали эту аббревиатуру и даже обозначали (тезисно) проблемы, с которыми приходится сталкиваться в рамках Java Memory Model. Более близкое знакомство с ней рано или поздно придется совершить;
· Механизмы, которые лежат в основе изученных инструментов. Мы, так или иначе, столкнулись с многими из них, лежащими на различных уровнях абстракции – от структур данных (вроде SkipList, лежащего в основе ряда коллекций) до инструкций процессора (вроде CAS). Данный раздел можно считать безграничным, но тем лучше для заинтересованных;
· Оптимизации в рамках JVM. Достаточно специфичная тема, в которой можно объединить настройки JVM (от количества доступных JVM ядер до конфигурации ForkJoinPool.commonPool() через настройки JVM) и оптимизации работы процессора инструментами JDK. Условной точкой входа в последнее можно считать volatile, продолжением – инструменты для решения проблем вроде False sharing, предоставляемые JDK. Я считаю данное направление специфическим и узким даже для среднего сеньора (в отличии от двух пунктов выше), но не вижу причин не осветить;
· Выход за пределы JDK и Java. В реальных задачах разработчик далеко не всегда может позволить себе оставаться в уютном маня-мирке. И здесь включаются в работу внешние библиотеки в рамках Java-экосистемы: Google Guava, Quartz, инструменты для многопоточности, предоставляемые Spring Framework – не суть важно, набор инструментов широкий и знакомство с ними затянется надолго. Но и это не предел. Поднимаясь еще выше, придется сталкиваться с проблемами синхронизации в рамках инстансов (одновременно работающих экземпляров) вашей системы, между системами и прочими проблемами, которые очевидно актуальны в рамках конкурентности, но выходят далеко за пределы конкурентности (а тем более – многопоточности) в Java.
Список направлений, в которых можно развиваться в контексте конкурентности и многопоточности можно продолжать и дальше. Пунктами выше я попытался донести три тезиса:
1. Имеющиеся знания дают хороший базис, позволяющий использовать изученные инструменты в учебных и реальных задачах, а также углубляться в раздел дальше;
2. Те, кто заинтересованы данным направлением, имеют сразу несколько возможных векторов развития. Насколько удачно и понятно для новичков удалось сформулировать и описать эти векторы – вопрос открытый, можно засылать фидбек:)
3. Тема конкурентности практически безгранична вне зависимости от того, в какую сторону копать: алгоритмы, низкоуровневые механизмы, инструменты JVM, инструменты в java-экосистеме и т.д.
Как бы там ни было, я надеюсь, что смог облегчить путь в многопоточность тем, кто прошел этот раздел в рамках курса. И особенно тем, кто не сталкивался с многопоточностью ранее.
Небольшое послесловие
Вы прочли вторую версию этой статьи. Первая оказалась слишком угнетающей, на мой взгляд:)
Возможно, я не тот человек, который может привить интерес к многопоточности и зарядить на дальнейшее его изучение. Но я попытался:)
Раздел получился сложным, по крайней мере, для меня. Возможно потому что раньше мне практически не приходилось объяснять рассмотренные темы, за редким исключением. А возможно, потому что не считаю свой профессиональный уровень в теме конкурентности слишком высоким. Как бы там ни было, этот раздел завершен и дальше должно быть легче:) Возможно, когда уроки, связанные с многопоточностью, пройдет больше людей, станет понятно, стоит ли их переработать. Но это будет потом.
А пока можно себя поздравить – мы завершили очередной раздел. И можем идти дальше.
На сегодня все!

Если что-то непонятно или не получается – welcome в комменты к посту или в лс:)
Канал: https://t.me/ViamSupervadetVadens
Мой тг: https://t.me/ironicMotherfucker
Дорогу осилит идущий!