Сравните между собой первые и последние рассказы цикла помпадуры и помпадурши

Эксклюзивное интервью агентству интерфакс-украина главы фракции слуга народа давида арахамии текст: елена савченко - недостойное поведение уже бывшего заместителя министра

Арахамия: Нужно точно очертить территорию – куда олигархи смогут заходить, а куда им ходить не надо

Эксклюзивное интервью агентству «Интерфакс-Украина» главы фракции «Слуга народа» Давида Арахамии

Текст: Елена Савченко

Недостойное поведение уже бывшего заместителя министра внутренних дел Александра Гогилашвили имело большой резонанс в СМИ. Как вы думаете, что надо сделать, чтобы представители исполнительной власти, да и законодательной тоже (народные депутаты), поняли, что такие вещи допускать нельзя?

— Как мне кажется, в этой ситуации как раз ключевая роль отведена журналистам. Когда такие истории получают огласку, имена «героев» становятся нарицательными. Для людей это маркер, условный стандарт, как не нужно делать. То есть благодаря огласке имеем и best practices – хорошие практики, и worst practices – плохие практики.

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

Реакция Президента была быстрой и правильной. Хотя некоторые посчитали данную ситуацию постановочной. Но это совсем не так, поскольку ущерба от инцидента больше, чем дивидендов.

Но существует кодекс госслужащего.

— Существует, и он довольно грамотно составлен.

Может, действительно, ссылаясь на него, просто брать и увольнять людей, если они выходят за рамки правил.

— В Кодексе госслужащего выписаны очень правильные вещи, но есть и обратная сторона медали. Кадровой конкуренции на госслужбе практически нет, поскольку зарплаты у сотрудников низкие. Речь не идет о новосозданных и реформированных органах. Если увольнять, то мы вообще обескровим госслужбу. Я уже не говорю о существовании большой миграции, когда из нереформированных органов люди переходят в новообразованные или реформированные структуры, где зарплаты в разы больше. Например, из Службы безопасности Украины переходят в Государственное бюро расследований, потому что сотрудник СБУ, который 20 лет проработал, получает условных 15 тыс. грн, а сотрудник ГБР, который только устроился на работу, 80-100 тысяч.

Возвращаясь к теме поведения чиновника. Она же актуальна и для депутатов. Вы во фракции какую-то воспитательную работу с ними проводите?

— К сожалению, у нас недостатка в медиа-скандалах нет. В воспитательной работе тоже нужен какой-то баланс. Если в начале нашей каденции за любой скандал, где был замешан депутат, мы исключали из фракции, то потом от этой практики отошли. Поскольку убрать человека из фракции – фактически вычеркнуть один голос. В результате, поставить под угрозу принятие решений, реформ, которые мы обещали нашим избирателям. Так можно просто потерять коалиционное большинство, и теперь мы только в крайних случаях идем на такую меру.

Кстати, о большинстве. Люди от вас по разным причинам уходят: кто-то сам, кого-то вы исключаете. Все сложнее находить голоса за то или иное решение и в двух депутатских группах («За будущее» и «Доверие»), которые вас обычно поддерживают.

— Чем ближе к выборам, тем этот процесс органичнее. Опытные в политических процессах политики говорят, что так всегда и было. Кто-то уже нарабатывает оппозиционную позицию, чтобы сыграть на следующих выборах. Хотя, честно говоря, с новым Избирательным кодексом я не понимаю такой стратегии, поскольку сегодня это уже не так важно. Есть защищенная первая девятка в партийном списке, которая проходит в любом случае в парламент, а все остальные кандидаты должны набрать 25 тыс. голосов. Если у тебя эти голоса есть, то все равно, в какой партии состоять.

Многие народные депутаты этого не понимают, они еще в новом Избирательном кодексе не жили (по нему прошли только местные выборы) и думают по старинке: «Я вот сейчас уйду в оппозицию, включу оппозиционную риторику, и она мне быстро рейтинг поднимет». Они рассчитывают за счет этого получить какие-то политические дивиденды. А по факту окажется, что это совсем не так.

Опросы показывают, что даже хорошие дела и крутые инициативы на росте рейтинга сразу не сказываются. Мы по рынку земли это отследили: вначале была серьезная кампания по дискредитации концепции, и наш рейтинг процентов на 10% упал. А потом рынок земли запустили, и рейтинг сразу пошел в рост.

Сейчас команде предстоит пережить подобное – большой бой за пенсионную реформу, за накопительную пенсию. О ней говорят уже 20 лет, но ни одного закона не приняли. Мы планируем ее запустить.

Когда?

— В 2022 году. В пакете для запуска накопительной пенсионной системы – 5-6 законопроектов, которые нужно принять.

Недавно встречался с представителями крупной бизнес-корпорации из Казахстана, которая интересуется нашим сельским хозяйством. Рассказывали о сумасшедшем строительном буме в своей стране, несмотря на эпидемию ковида: 1 кв. метр жилья high-end класса с меблировкой стоит $1 тыс. И это благодаря реинвестициям пенсионных фондов. У них уже 15 лет работает накопительная пенсия, и часть средств пенсионных фондов людям разрешили инвестировать в недвижимость. Вот яркий пример, когда деньги, хранящиеся под подушками, начинают работать в экономике.

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

Но для этого нужна хорошо работающая правоохранительная система, чтобы запустить государственные фонды, потому что даже в Европе были случаи мошенничества.

— Конечно. Мы на это хорошо реагируем, говоря: «Давайте стартанем исключительно с государственных фондов!». Людям откроют персональные счета, к которым они получат доступ. На эти счета упадут какие-то деньги от государства. И тут возникнет вопрос, как же эти деньги защищать от инфляции. Вначале им надо предоставить возможность в гарантированный, защищенный способ компенсировать инфляционные процессы, допустим, через ОВГЗ (облигации внутреннего государственного займа, – ИФ). А со временем граждане поймут, что деньги, которыми они оперируют, можно вкладывать в какие-то другие проекты. И это будет уже осознанный выбор.

Но в начале, простыми словами, необходимо людям сделать инвесторские счета. Они должны стать инвесторами своего будущего. Это процесс, в том числе и ментальных изменений. Молодежь, наверное, быстрее это примет. Люди пожилые, скорее всего, будут использовать стратегию низких рисков. А если у человека только первая работа, ему 18-20 лет, то он вполне может рискнуть, почему бы и нет? А дальше – вопрос защиты государством этих инвестиций, аналогичный Фонду гарантирования банковских вкладов физических лиц.

Да, в этом вопросе есть объективные трудности, но через них прошли многие страны-соседи, надо просто заимствовать их опыт и внедрять лучшие практики. Иначе у нас никогда не будет нормальной пенсионной системы.

Возвращаясь к депутатам, у вас есть информация, что некоторые богатые люди пытаются подкупить ваших депутатов?

— Есть, конечно. Суммы от $500 тыс. до миллиона – за то, чтобы выйти из фракции и к кому-то в будущем присоединиться. У нас в IX созыве Верховной Рады появилась первая тушка. Роман Соха вышел из фракции. Рассказал, конечно, красивую легенду, почему так поступает и с чем он не согласен. Два с половиной года был согласен с курсом партии, а потом вдруг он его не устроил. Как говорится, «добрым словом и пистолетом вы можете добиться гораздо большего, чем одним только добрым словом». В данном случае «пистолетом» являются большие деньги.

Сейчас большинство в парламенте у вас есть. Допустим, 20-30 человек уйдут. Что дальше? Распад монокоалиции?

— Вероятность такого сценария процентов десять. Потому что начинается предвыборный цикл, и никто не хочет быть политическим камикадзе. Ты вышел из партии и на тебе сразу штамп «предатель». Люди это так воспринимают, мы видим в округах.

После того как Соха вышел из фракции, люди в Запорожье на его мажоритарном округе (75-й избирательный округ, – ИФ) собрали уже больше 10 тысячи подписей – инициируют процесс отзыва.

Сегодня уже совсем другой избиратель, не тот, кто за гречку голосует. Такие тоже, конечно, есть, но их значительно меньше. Мне кажется, что люди осознаннее стали на все смотреть. Децентрализация помогла – они увидели, что только от их выбора зависит, жизнь станет лучше или хуже…

Но даже если допустить, что монобольшинство развалится, тогда придется создавать более широкую коалицию, уже настоящую коалицию.

А с кем?

— Конечно же, с группами. Ответ – на поверхности. У нас с группами на многие вопросы видение совпадает. Анализируя только голосования за законопроекты видно – с ними у нас больше всего пересечений. Они мажоритарщики, у них нет линии партии.

Но я такой прямой фатальной угрозы развала коалиции не вижу. Во-первых, этот процесс не одномоментный, а растянутый во времени, и все смогут наблюдать и знать, почему она распадается и кто (самое главное!) бенефициар этого процесса.

Уже и сейчас видим, как это происходит. Мы не случайно объявили бойкот некоторым медиа-группам. И многие люди нас поддерживают. По последнему исследованию КМИС (Киевский международный институт социологии, – ИФ), у нас вырос рейтинг.

Знаете, после принятия антиолигархического закона люди хотят увидеть конкретные меры борьбы с влиянием олигархов. Это вовсе не значит, что нам надо всех олигархов посадить в тюрьму. Просто надо точно очертить территорию, куда они могут заходить, а куда им ходить не надо.

И тут должно быть четкое понимание: если ты бизнесмен – оставайся бизнесменом. Более того, мы как власть заинтересованы, чтобы бизнесмены, работающие «в белую», увеличивали свое присутствие на нашем рынке, реинвестировали в Украину и платили больше налогов, что приведет к увеличению общественных благ для всех.

А как доказать, что бизнесмен является олигархом? Он – не депутат, не член какой-либо партии, открыто не поддерживает ту или иную политическую силу.

Для этого же и существует новая независимая антикоррупционная инфраструктура, в которую входят НАБУ, САП, ВАКС (Национальное антикоррупционное бюро Украины, Специализированная антикоррупционная прокуратура, Высший антикоррупционный суд, – ИФ). Если человек, как вы говорите, бизнесмен и непубличный политик, а потом мы узнаем, что он де-факто спонсирует политическую силу, платит откупные за выход из фракции, переходы в другие образования, и в результате группа, которую он финансирует, голосует за законы, помогающие развивать его бизнес, то слово за НАБУ – все это подтвердить. И это — абсолютно доказуемая история.

Допустим, коалиция все-таки распадается, с группами или с отдельными депутатами вы не договариваетесь. Что тогда?

— Тогда по закону – досрочные выборы. Но большинство людей в этих группах и других партиях понимают, что многие из них не пройдут в следующий парламент, поэтому будут вынуждены найти какую-то конструкцию, чтобы коалиция существовала.

Обычно за какое-то время до выборов многие пытаются найти новых лидеров, и тут очень важна критическая масса, которая за этим лидером пойдет.

— Если вы помните, год – полтора назад тему досрочных выборов активно прокачивала ОПЗЖ (партия «Оппозиционная платформа – За жизнь», – ИФ). Тогда еще не были введены санкции против телеканалов («112 Украина», ZIK и NewsOne, – ИФ) Медведчука (народный депутат, председатель политсовета ОПЗЖ Виктор Медведчук, в настоящее время по решению суда находящийся под домашним арестом, – ИФ). Каждое утро на этих телеканалах начиналось с того, что необходимы досрочные выборы. Причина – у этой политической силы в то время вырос рейтинг, ее лидеры решили, что в случае перевыборов они в парламент заведут больше людей. И эту медиаповестку они активно озвучивали. Потом каналы закрыли, рейтинг просел и из повестки дня этот пункт ушел.

В общем, в досрочные выборы парламента вы не верите.

— Я расцениваю их вероятность менее одного процента.

А что вы думаете о популярной сейчас теме переноса парламентских выборов. Если депутаты обратятся в Конституционный Суд за разъяснением, в какой очередности должны проходить президентские и парламентские выборы, вы поставите свою подпись под таким представлением?

Я не буду подписывать. У меня не хватает компетенции оценить, насколько это плохо или хорошо. Существуют разные мнения, как у политтехнологов, так и у юристов. Часть говорит, что срок полномочий законодательного органа пять лет, а все остальное – от лукавого. Другие считают политическим самоубийством вмешательство в избирательный процесс. И кто из них прав, я не знаю, поэтому воздержусь от комментария. Надо будет доработать еще полгода, доработаем! Нет – пойдем раньше на выборы.

«Слуга Народа» точно не будет драйвером этого процесса. О таких возможных инициативах говорят мажоритарщики, считая, что юридические основания для обращения в КС есть. Но тут мы сталкиваемся с челенджами, такими как фактически не работающий в настоящее время Конституционный Суд, как восприятие электоратом. Понятно, что оппозиция в любом случае будет нас обвинять в какой-то схеме, если мы подпишем такое обращение. А если не подпишем, то скажет, что нам это выгодно.

Но электорально это действительно не очень выгодное дело.

— С другой стороны, только Конституционный Суд может прояснить этот вопрос. Иначе каждый будет использовать ситуацию в своих целях, кто-то будет дискредитировать, кто-то, наоборот, продвигать, в то время как у нас есть для этого специально уполномоченный орган с немалыми зарплатами судей. Надо максимально быстро разблокировать работу КС. Какое решение примет, такое и выполним. Тут нет большой интриги. Пока, на момент нашего интервью, мы живем в парадигме, что Конституционный Суд не работает, этого представления вообще не существует. И хотя теоретически такая опция может быть, мы исходим из того, что выборы в Верховную Раду будут в 2023 году.

— Какое-то время в парламенте витала инициатива возврата к смешанной избирательной системе (совокупность двух систем: пропорциональной – по партийным спискам и мажоритарной – голосование за кандидата).

И витает, и активизируется с каждым днем. Народные депутаты считают, что на огромных избирательных округах, которые существуют в настоящее время, невозможно добиться узнаваемости. Сегодня у мажоритарщика, который на одном округе избирался 10 лет, округ увеличился в три раза – ни он людей не знает, ни они его. Времени, чтобы познакомиться, нет. Получается, созданы какие-то псевдоокруга, которые не работают, и существует вероятность избрать в законодательный орган случайных людей. Так что аргументы весомые и объективные, но одно дело разговоры на кухне или в столовой парламента, а другое – законодательная инициатива. Инициатив мы пока не видели. Хотя и наши многие мажоритарщики тоже этого хотят.

Другие фракции тоже поддержат эту идею.

— Весь парламент поддержит. Думаю, будет голосов 300+.

Я даже не знаю предостережений, которые бы помешали возвратиться к смешанной системе. С новой системой проэкспериментировали на местных выборах – увидели очень много негатива. Основной минус – кандидаты, попадающие в списки партий, друг друга «уничтожают». Условно говоря, третий номер начинает «сыпать» компромат на пятый номер, тот – в ответ. В результате идет борьба внутри списка, а не с внешними оппонентами. Мне этот механизм совсем не нравится. А теперь представьте партийный открытый список, который включает много претендентов. Это выглядит плохо, и в конечном итоге, дискредитирует и «валит» всю политсилу.

Следующие выборы будут электронными?

— Давайте здесь сразу расставим точки над і. Оппоненты разгоняют идею, что будет голосование при помощи мобильного телефона. Это априори невозможно, потому что согласно Конституции у нас процесс голосования тайный, вы не должны быть в этом процессе идентифицированы. Мобильный же по умолчанию идентифицирует. А вот провести электронный подсчет голосов возможно, как это делают в США и многих других странах. Это позволило бы уйти от манипуляций, выяснений отношений на уровне избирательных комиссий, подкупов наблюдателей, избирательных каруселей и многого другого. Электронный подсчет голосов сделал бы избирательный процесс более прозрачным, позволил бы более оперативно обрабатывать данные. Неизвестно пока, успеем ли мы его запустить к ближайшим выборам. Ведь надо приобрести оборудование, процедура закупки которого через Prozorro обычно занимает полгода. Мы не до конца еще провели диджитализацию, чтобы все данные шли через защищенные каналы связи. И, честно говоря, пока электронный подсчет голосов на избирательных участках выглядит маловероятным. Может быть, в виде эксперимента на каких-то участках, чтобы показать, как это может работать. Параллельно с привычным подсчетом голосов.

Как вы уже говорили, работа Конституционного Суда фактически заблокирована. Инстанция отсрочила приведение к присяге судей КС, назначенных президентом по его квоте из-за отсутствия вакантных должностей.

Так и есть, там людей оказалось больше, чем стульев.

Каким вы видите выход из создавшейся ситуации, когда и при каких условиях КС сможет приступить к нормальной работе?

Есть надежда, что к системной работе КС возвратится до конца первого квартала 2022 года. Мне кажется, что как только Верховная Рада делегирует по своей квоте двух кандидатов на должности судей КС, а голосование за их кандидатуры состоится в январе или в начале февраля, то количественный состав Конституционного Суда будет достаточным для легитимной   работы, и деятельность этого органа будет разблокирована. Если не появятся еще какие-то новые витки в этой борьбе. А потом уже можно в судебных инстанциях разбираться, кто признанный судья, кто непризнанный.

Сравните между собой первые и последние рассказы цикла помпадуры и помпадуршиОсновные кадровые ротации в Кабмине уже прошли. Не закрыта только вакансия главы Фонда госимущества…

— Подыскиваем кандидата. Уход главы ФГИ Дмитрия Сенниченко был предсказуем по одной причине – план приватизации и факт приватизации, как говорят, две большие разницы. В Фонде госимущества изначально заложен конфликт интересов: его руководитель осуществляет две функции – управление активами (сдача в аренду) и их продажа. С одной стороны он должен продавать все, что можно продать, и как можно быстрее, а это значит, продавать дешевле. А с другой стороны, есть активы, которые приносят хорошую прибыль от сдачи аренды, и если правильно работать с арендаторами, можно существенно повысить эти доходы. В итоге, в голове у человека двоякие мысли – продавать или управлять? Во избежание и надо разделить эти две функции: создать агентство управления активами, задача которого собрать максимальную сумму от аренды, и агентство по продаже. Проще, это будут большие государственные риэлторы, которые с помощью инвестбанкиров будут готовить объекты для продажи. В этом случае у каждого из агентств будет абсолютно четкий показатель эффективности. Если я управляю активами, значит, показатели моей работы – средства от сдачи в аренду, капитализация активов, а если я продаю, то о моей эффективности говорят цена продажи, ее скорость, количество проданных объектов. И все сразу становится на свои места. При нынешней структуре ФГИ, кто бы его ни возглавил, всегда есть повод критиковать руководителя фонда либо за одно, либо за другое.

Новое – это хорошо забытое старое. Подобное уже было в 1998 году, когда было создано Национальное агентство Украины по управлению государственными корпоративными правами. Просуществовало оно полтора года, и после его ликвидации функции и объекты возвратили ФГИ.

Надо создать объективный критерий, который бы исключил или хотя бы привел к минимуму какие-либо политические решения. Где существуют политические решения – там субъективизм, там возможна коррупция. Только сформированный алгоритм позволит избежать коррупционных рисков.

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

— По сути, они получат все права граждан Украины, кроме права принимать участие в избирательных процессах. В этом вопросе будут исходить из принципа оседлости: если гражданин живет за границей, то и участвует в избирательных процессах страны, где живет. Но, например, если гражданин Канады живет в Украине уже пять лет, и скорее всего он здесь резидент, платит налоги, понимает политические процессы, тогда он имеет право голоса на выборах в нашей стране.

А как это будет согласовываться с законодательствами других стран?

— Здесь основной вопрос в синхронизации законодательств.

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

Это все и предстоит еще прорабатывать. Важно, что законопроект дает право Кабмину составлять список стран, граждане которых могут иметь множественное гражданство. То есть мы принимаем общий рамочный закон, а далее Кабмин договаривается на двусторонней встрече с правительством того или иного государства. Договорились правительства Украины и Канады – подписали договор.

И так с каждой страной?

— Причем с каждой страной отдельно: Украина – США, Украина – Австралия… И так, постепенно, мы заключим соглашения с теми государствами, в которых есть большие украинские диаспоры – Португалия, Аргентина, Канада, Австралия, США, Италия. При подписании двусторонних соглашений обязательно будут учитываться особенности законодательств этих стран.

— А как быть со службой в армии, если у нас сохранится призыв на срочную воинскую службу?

— Этот вопрос тоже надо продумать. Если человек живет в другой стране постоянно, то неправильно его призывать в армию в Украине… Тем более, он мог служить по контракту в стране проживания.

Этот закон на следующей сессии будете принимать?

— Да. Это было наше партийное предвыборное обещание, его ждут представители украинской диаспоры. Когда президент бывает с визитами за границей и встречается с ними, постоянно поднимается данный вопрос: люди мечтают получить украинский паспорт.

А какая у них мотивация? Зачем им это? Это какая-то моральная или экономическая история?

Понятно, что рейтинг паспортов граждан Канады, США, Австралии при перемещении по миру значительно выше, чем украинских, и для жителей этих стран этот вопрос не стоит.

Но есть государства, где украинский паспорт будет давать больше возможности для его обладателя, чем паспорт страны проживания – с ним можно ездить в странах Шенгена. Так что не исключаю и какие-то меркантильные соображения.

Ну и, конечно, одна из мотиваций – причастность к своей исторической родине, о которой мечтает не одно поколение украинских эмигрантов.

Считаю, что услуга выдачи такого паспорта должна быть платной – на этом государству нужно зарабатывать, а наши консульства смогут от этих средств пополнять свои бюджеты.

Последняя пленарная неделя у депутатов закончилась 17 декабря, и соберутся они на пленарное заседание более, чем через месяц. Насколько оправдана такая зимняя пауза?

— Во-первых, большинство законов, которые подготовлены в профильных комитетах, мы уже проголосовали или провалили. И в зале заседаний у депутатов не главная работа, основная деятельность проходит в комитетах, зал – это уже непосредственно фиксация закона, его легализация. А подготовка самого документа, его обсуждение идут в парламентских комитетах. За предстоящий месяц – у нас две недели работы в комитетах и фракциях и две недели – с избирателями.

Пока я не попал в парламент, мне тоже казалось, что работа народного депутата проходит исключительно в зале заседаний. Однако, на самом деле, работа «под куполом» (зал пленарных заседаний находится под прозрачным куполом здания парламента, – ИФ) не совсем эффективна. Иногда ты просто вынужден сидеть в зале, когда рассматривают поправки к законопроекту, но ты их не поддерживаешь. Практически это простой, а платят народному депутату за присутствие в зале, что совсем неправильно. По- хорошему, надо платить за работу в комитетах, в округах. А промежуточный процесс дебатов – это чисто политическая история.

Совсем по-другому организована работа в сенате США. У них есть дни обсуждений, на которые приходят те, кто хочет высказать свою позицию, и не появляются те, у кого позиция по тому или иному вопросу непоколебима и повлиять на нее не могут никакие дебаты. Я стал свидетелем в сенате, когда документ обсуждали всего пять – шесть человек. А вот уже в дни голосований – явка обычно максимальная.

Еще полтора года назад я предложил версию изменений в регламент Верховной Рады – сделать четверг днем голосований, среду – днем обсуждений (дебатов). У нас в парламенте как таковых дебатов нет, а могли бы быть. Например, на повестке дня – большая и архиважная тема – пенсионная реформа. На день дебатов приглашаем не только депутатов, но и экспертов, специалистов, слушаем мнения разных сторон.

По моим ощущениям, процентов 70 времени нахождения в зале заседаний бесполезно – ты заранее знаешь, какую кнопку будешь нажимать: желтую или зеленую. Это неправильно. Во мне борется все время оптимизатор. Я считаю, что с точки зрения организации работы это очень некорректный процесс.

Имея опыт работы с нынешним составом Верховной Рады, со своей фракцией, готовясь к следующим выборам, при подборе кандидатов в вашу команду, каких ошибок вы постараетесь не допустить?

Хороший вопрос. И над ним мы много рефлексируем. Во-первых, будем подбирать людей, которые работают с избирателями на постоянной основе. Знаете, не буду называть фамилий, но есть мажоритарщики, которые за два года два раза были в своем округе. А есть и такие среди исключенных из нашей фракции, которые пришли на прием с избирателями не на своем округе. Большим политиком становятся, а своего округа не знают. Таких людей не хотим больше иметь в списке.

Во-вторых, к отбору кандидатов будем подходить с точки зрения ценностных характеристик, хотя это не так легко сделать. Но у нас будет больше времени, чтобы найти бэкграунд на каждого, проанализировать рекомендации, узнать, конфликтный тот или иной человек, проверить, соответствует ли он критериям, из которых мы исходим при отборе в команду. Все, как это обычно происходит при подборе кадров в любом деле. В 2019-м, когда формировали команду «слуг», запаса времени не было, все очень быстро происходило.

Очень важно еще и чувство команды, иногда страдает рабочий процесс из-за того, что у нас бывает разнобой. Но при этом в ней должны быть люди из разных социальных слоев. За это нас часто критикуют, но я с этой критикой не согласен. Это необходимо, чтобы не было никаких перекосов. Если в команде одни бизнесмены, они не видят решений социальных вопросов и стремятся минимизировать их, если взять в команду исключительно людей из социальной сферы или культуры, то они считают, что все вопросы должно решать государство. А так в споре одних с другими будет рождаться истина, находиться какой-то компромиссный вариант для решения проблемы. Поэтому диверсификацию по людям из разных слоев с разными бэкграундами необходимо сохранить. Конечно, удобнее, с точки зрения управления, когда все в команде мыслят одинаково, но с точки зрения репрезентативности – это будет провал.

Как правило, у людей из социальной сферы нет средств, и они не могут самостоятельно провести свою предвыборную кампанию. Этот вопрос тоже надо будет решать.

— Не секрет, что условно один бизнесмен, баллотируясь в парламент, спонсирует еще одного — двух человек: например, учителя и врача. И это с точки зрения командности нормально.

Многих возьмете из нынешнего состава фракции в будущую команду?

— Половину точно. Нас много критиковали, но с учетом ограниченного временного промежутка на отбор перед прошлыми выборами, у нас не все так плохо. Конечно, есть люди, которые попадали в медийные прецеденты. Но есть и ребята, у которых сформировалось государственное мышление, которые за два с половиной года заметно выросли. Это видно во время дискуссий на заседаниях фракции. И мне это нравится.

У нас есть и большая образовательная программа, мы работаем с Киевским национальным университетом им. Шевченко, у нас многие депутаты учатся. И я тоже, кстати, учусь в академии госуправления при президенте, которая относится к КНУ им. Шевченко. Мы с ними совместно составляем модульную программу для ОТГ (объединенная территориальная громада, – ИФ), которую можно использовать дистанционно. Для представителей ОТГ это важно. В Верховной Раде есть аппарат, секретариат, помощники депутатов, и даже если ты совсем не ориентируешься в чем-то, тебе помогут, направят, и ты будешь все равно действовать в рамках уже наработанной системы. А депутату местного уровня или главе ОТГ, ранее ничего общего с деятельностью громад не имевших, надо научиться управлять, осваивать бюджет, делать закупки через Prozorrо, правильно оформлять субвенции. Эти знания и помогает получить наша модульная программа.

В будущий год многие люди смотрят с тревогой. Может быть, потому что бояться холодной зимы, высоких тарифов на коммунальные услуги, отключений электричества. Чтобы вы сказали таким людям?

— В этом случае я всегда говорю, вспомните 2014 год – это же был год настоящей тревоги, когда вот-вот война. Если сравнить с сегодняшним ощущением, то это две большие разницы. Надо просто помнить, что каждый год у нас тревожный. Но… Смотрим вперед! Государство крепкое, экономика крепкая, даже несмотря на постковидные процессы. Мы принимаем необходимые для страны законы. Президент инициирует введение экономического паспорта…

А вы сами верите, что экономический паспорт украинца станет реальностью?

Сегодня это самый большой фидбэк, который мы получили. Конечно, есть за что эту инициативу критиковать, например, она распространяется на детей 2019 года рождения, а не на всех детей. Но логика наша проста – с какого-то момента надо начинать, а потом эту инициативу расширять, как на других детей, так и на пенсионеров. Поскольку у пенсионеров, особенно старше 70-80-ти лет, вообще нет возможности в дополнительных заработках, и им надо получать безусловный базовый доход. Но недовольные и критики будут всегда, тут важно, что мы первые сделали этот шаг, и средства за использование украинских недр будут направляться на персональные банковские счета детей, которые в будущем они смогут использовать на обучение, покупку жилья.

Но реально это же заработает через 17–18 лет.

Знаете, когда первый раз почувствуют значимость закона? Ровно через год после его принятия. Когда на персональных счетах детей родители увидят условную тысячу долларов.

Как раз к следующим выборам и увидят.

Нет, это не связано с выборами. Мы обещали это сделать давно и много раз ругались на фракции, потому что все время откладывали: были альтернативные концепции.

Есть и такое мнение, что экономический паспорт со временем отменят. Никто этого не сделает, потому что это будет политическое самоубийство – забрать деньги у детей. Даже если будет кризис экономический. Представляете, если четырем миллионам избирателей, у миллиона детей которых на счетах лежат накопленные государством средства, придти и сказать: «Я у вас забираю эти деньги или переполовиниваю». Невозможно такое будет сделать.

Что ожидаете вы от следующего года и какие изменения он принесет обычному украинцу?

— Мы к следующему году отремонтируем все дороги национального значения. Думаю, что где-то процентов сорок отремонтируем и местных дорог. Есть даже амбиция сделать больше. Поставим больше камер на дорогах, которые будут фиксировать скорость автотранспорта, что позволит в два раза снизить смертность в результате ДТП. Как показывают соответствующие расчеты, такого показателя достигнуть реально. В первом квартале следующего года анонсируем большую налоговую реформу для бизнеса – его представители, думаю, будут довольны.

А в чем идея?

— Идея проста и лежит на поверхности. Условно, это такая индульгенция – если ты платишь налоги, то у тебя есть гринпас и к тебе вообще никто не имеет права подходить и проверять твой бизнес. Не платишь налоги – у тебя, соответственно, много проблем, твой бизнес проверяют. В результате, человек понимает, что он в зеленой зоне – с благоприятным климатом, в желтой – с потенциальным риском или в красной – тогда пощады не будет, и государство применит к нему всевозможные «карательные меры». Не посчастливится тому, кто придет с проверкой к владельцу грин паспорта, независимо от того, какой орган проверяющий представляет, ему будет грозить наказание вплоть до увольнения.

Большую ставку делаем на приток туристов в Украину. Люди соскучились по путешествиям. Мы видели, как в этом году правильно продуманная инициатива в несколько раз увеличила количество туристов из арабских стран и привела очень много денег в Украину. У нас есть несколько подобных «пилотов», которые позволят сервисным индустриям дышать свободнее, дадут им возможность заработать после двух ковидных лет. Мы готовим большую программу по учителям, она следующая после программы для медиков.

Вы имеете в виду повышение зарплат?

— Может, повышение зарплат для учителей будет чуть меньше, чем медикам. Но повышение планируем радикальное. Надеюсь, все получится.

Планируется много вещей, связанных с транспортными перевозками, будут введены в эксплуатацию новые электрички. Вы же знаете, что в сегодняшние электрички даже страшно зайти. Перед нами стоит амбиционная задача – сделать этот вид транспорта комфортным, в который из своих машин пересядут «белые воротнички». Соответственно будет меньше пробок. И те, кто пользуется ежедневно электричками, ощутят на себе все позитивные изменения. А у нас ежемесячно порядка четырех миллионов человек ездят в столицу только из пригородов Киева. Думаю, мы успеем это сделать до конца нашей каденции.

Если все будет нормально, начнет действовать накопительная пенсионная система, начнут аккумулироваться средства на счетах. Это не коснется нынешних пенсионеров, но им можно будет индексировать пенсию. Инвестированные в экономику средства через несколько лет приведут к существенным увеличениям пенсий.

Диджитализация. Это не только ковидные сертификаты в Дие. Мы хотим перевести хотя бы до 90% контактов человека с государством в телефон. Это приведет к существенному уменьшению бытовой коррупции. Мы уже по диджитализации опередили заграницу.

Сейчас собираешься ехать в другую страну, берешь с собой бумажные водительские права, паспорта. А у нас все в телефоне. И такие изменения оценивает в первую очередь молодежь.

Сегодня одна из наших основных задач – уменьшить количество молодых людей, уезжающих работать за границу, а этого возможно достичь, если им будет комфортно жить и работать в Украине, если они здесь будут защищены, смогут без препятствий открыть бизнес, если будут получать достойную зарплату и иметь хорошие условия труда, которые создаст для них государство.

Парламент на прошлой неделе принял законопроект о Дие-Сity (законопроект №5376 «О внесении изменений в Налоговый кодекс Украины относительно стимулирования развития цифровой экономики в Украине», – ИФ). Он регулирует налоговые условия специального правового режима «Дия City», вводит особые условия налогообложения компаний-резидентов, доходов их работников и будет стимулировать инвестиции в IT-отрасль.

Вы опровергнете или подтвердите идею министра финансов Сергея Марченко, что после налоговой амнистии у украинцев проверят все доходы с 1995 года.

— Опровергну. Это невозможно. Мне понятно, почему министр финансов так говорит. Он отвечает за сборы. Но, во-первых, это сделать практически невозможно. А во-вторых, у нас категорический протест против этого внутри фракции. Скажу так – этого не будет.

Данный цикл статей рассматривает сложнейший мир многопоточного программирования через достаточно щекотливую тему, читатель должен быть готов к тому, что некоторые образы и примеры могут негативно повлиять на его психологическое состояние, некоторые — вызвать отвращение. Следует учитывать, что все описанные ситуации являются вымышленными и совпадения с реальностью случайны. 

Повествование будет разбито на две части, от простого к сложному. 

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

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

О чудный дивный мир

Теплый летний вечер, закат. Приятный, едва прохладный, морской бриз ласкает  волосы коренастого мужичка, который стоит на теплом песке, закрыв глаза. В своей памяти он пытается воспроизвести и хотя бы на секунду задержать тот самый момент, когда последние лучи солнца, уходящего за горизонт, поджигают небо ярко оранжевым пламенем. Несколько секунд и небо почти мгновенно окрашивается в фиолетово-черную пустоту. Еще пару мгновений и темнота скроет всю природную красоту этого места и прекрасный город Вхоревосток начнет медленно утопать в цветах оранжевых фонарей и люминесцентных ламп. Он совершенно забыл, как выглядит этот момент. Между ним и солнцем, которое уже почти скрылось за горизонт, пришвартован огромный контейнеровоз. 

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

И вот он докуривает папироску, бросает её в песок, смачно харкает в другую сторону и со словами: “Ну, началось, б***ь!” идет открывать дверь этим похотливым мужикам. Встает за стойку регистрации, прокашливается, пока они, по привычке, выстраиваются в очередь и тихим, низким, прокуренным голосом подзывает первого посетителя к себе. Отличное начало еще одной тяжелой трудовой ночи.

Добро пожаловать. Основные принципы

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

Здесь следует отвлечься и прояснить некоторые детали: 

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

Бордель, если говорить про тип заведения, мы, программисты называем просто — program, а конкретно наш, припортовый, зовем process

Когда мы рассматриваем администратора, проститутку или любого другого сотрудника как живого человека, который может выполнять простые действия, то мы подразумеваем, что это thread

А вот процесс выполнения этих, логически связанных друг с другом действий, например возвратно-поступательные движения, именуемые сексом, называем algorithm.

// algorithm
Runnable life = () -> {
    while (isAlive()) {
        work(Duration.ofHours(19));
        sleep(Duration.ofHours(5));
    }
};

// thread
var human = new Thread(life);
human.start();

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

Если throughput будет маленьким (передержали в холодном море), а latency очень большим, особенно когда очередной контейнеровоз прибыл в порт и его команда решила этой ночью расслабится в нашем заведении, то будь уверен: треть из них будет громко материться, треть — набухается до поросячьего визга, а еще треть просто уйдет выломав дверь. И никто не будет доволен; у многих людей по всему району, с огромной вероятностью, еще и лица будут разбиты (такая ситуация называется bottleneck).

Поэтому пытаемся всеми силами повышать трупут и снижать латенси. Можно делать свою работу очень быстро, оптимизировать каждое движение, обучить проституток различным техникам, но все мы знаем, что это не всегда помогает. 

Ситуацию можно решить построив рядом еще один бордель, с другими администраторами, проститутками и декорациями в комнатах. Этим мы увеличим пропускную способность, как и затраты на содержание, что уже выглядит не так привлекательно. Потребуется человек, который будет направлять посетителей в один из этих борделей (это же обязанность reverse proxy).

Решение отличное, но о нём как-нибудь в следующий раз. Сейчас будем рассматривать только то, что происходит в отдельно взятом борделе, даже если их целая сеть по стране.

И да, везде будем использовать очереди (структура данных, знакомая всем с детства, работающая по принципу “первый вошел, первый вышел”, может иметь ограничение по количеству находящихся в ней человек), иначе посетители будут толпиться в самых неудобных для этого местах, затрудняя работу сотрудникам.

Перспективы роста, дружная молодая команда и на кухне печеньки есть

Итак, мы имеем относительно ровный поток посетителей и редко возникающую пиковую нагрузку. Поэтому администраторов, проституток и других сотрудников должно быть несколько на одну позицию, с возможностью быстро привлечь к работе еще большее их количество. Как будем решать? Способов несколько. 

Первый. Как только потребуется еще один администратор, размещаем вакансию, общаемся с кандидатами, принимаем на работу, обучаем, выдаем бейджик и пускаем за стойку (это создание нового thread-а). Способ, сразу скажу, может быть очень долгим. Да и сколько людей хотим нанять? Для максимальной пропускной способности и минимальной задержки, должно быть столько же сотрудников, сколько и посетителей (этот подход называется thread per client). Но в наше время хороший сотрудник на вес золота, непозволительная роскошь. 

Хотя на должность администратора можно взять несколько бомжей; они третий год живут на соседней заброшке в коробках из-под холодильников. А когда наплыв посетителей спадет, очередной сухогруз отправится в свое дальнее плавание, попросту их уволим. В будущем как-нибудь разберемся. Дай бог они не сопьются или их не растащат на органы врачи из ближайшей городской больницы (примерно так я вижу себе ручное создание тредов посреди кода). С проститутками такой способ не прокатит: думаю мало кто захочет, чтобы их ублажал бомж.

Следующий способ, с точки зрения ресурсов, более затратный, но имеет огромное преимущество. Заранее нанимаем какое-то количество сотрудников, обучаем, сажаем в специальную комнату, вешаем табличку thread pool. Пока бордель пуст, они сидят в ней, попивают чай, болтают, смотрят новости по телевизору. Как только приходят посетители, надевают на себя пиджаки с различными бейджиками, выходят из комнаты и начинают обслуживать посетителей (такой подход называется worker thread).

Кстати о том, как устроены эти комнаты. В каких-то случаях такой комнатой может выступать небольшая каморка со шваброй, чистящими средствами и запасами гандонов на 20 лет вперед. Туда вряд ли поместится больше одного сотрудника (это будет single thread pool).

log.info("так создается тред пул из одного треда (single thread pool)");
var singleThreadPool = Executors.newSingleThreadExecutor();

log.debug("а так мы можем начать выполнение кода в этом тред пуле");
singleThreadPool.execute(() -> {
    log.debug("этот код будет исполнятся в отдельном треде");
    doProstitute();
    log.debug("закончили с этим...");
});

log.debug("вот этот код будет выполнен, когда предыдущая задача будет выполнена");
singleThreadPool.execute(() -> {
    log.debug("этот код так же будет выполнятся в другом треде");
    meetClients();
});

log.debug("При этом мы не заблокируем выполнение этого треда");

В других же это будет огромный зал, который может вместить в себя десятки, а может быть и сотню сотрудников разного сорта. И если количество сотрудников неизменно, это fixed thread pool. Если оно может меняться, то это будет scalable thread pool. Как пример, посадим в неё смотрителя, который будет следить за наполнением этой комнаты. Мало работы — половину увольняет, не хватает рук — бежит на заброшку за бомжами или звонит в ближайшее hr-агентство.

log.info("а теперь посмотрим на fixed thread pool");
var fixedThreadPool = Executors.newFixedThreadPool(2);
log.debug("запускаем выполенение кода в отдельном треде");
fixedThreadPool.execute(() -> {
    log.debug("этот код будет исполнятся в отдельном треде");
    doProstitute();
    log.debug("закончили с этим...");
});

log.debug("и одновременно запускаем еще одну задачу ");
fixedThreadPool.execute(() -> {
    log.debug("этот код будет исполнятся в отдельном треде, одновременно");
    meetClients();
    log.debug("с этим тоже закончили...");
});

log.debug("а вот эта задача подождет, пока в тред пуле появится свободнй тред");
fixedThreadPool.execute(() -> {
    log.debug("но так же будет выполнена в отдельном треде");
    testVenerealDiseases();
});

log.debug("а этот тред пойдет дальше");
log.info("и последний - scalable thread pool");
var scalableThreadPool = Executors.newCachedThreadPool();

log.debug("запускаем выполенение кода в отдельном треде, несколько раз");
for (int i = 0; i < 5; i++) {
    scalableThreadPool.execute(() -> {
        log.debug("этот код будет исполнятся в отдельном треде");
        doProstitute();
        log.debug("закончили с этим...");
    });
}

log.debug("накидаем еще немного задач");
for (int i = 0; i < 3; i++) {
    scalableThreadPool.execute(() -> {
        log.debug("этот код будет исполнятся в отдельном треде, одновременно");
        meetClients();
        log.debug("с этим тоже закончили...");
    });
}

log.debug("и еще одну, последнюю");
scalableThreadPool.execute(() -> {
    log.debug("проверим всех на венерические");
    testVenerealDiseases();
});

var tp = (ThreadPoolExecutor) scalableThreadPool;
log.debug("а тут мы посмотрим, сколько у нас тредов было создано: {}", tp.getPoolSize());
// у меня в консоле получилось 9
// пять проституток, три администратора и один лаборант

Правилом хорошего тона считается иметь разные комнаты для разных сотрудников, проституток и администраторов. И причина тут не в том, что они оргию устроят, когда клиентов нет. Тяжело понять на глаз, кто закончился, а кого в избытке, да и может сложиться ситуация, когда проститутка пойдет за стойку регистрации, схватив пиджак с чужим бейджиком, а администратора утащат в комнату отдыха пара огромных волосатых мужиков, которые не хотят ждать. Им все равно, а мы потеряем ценного сотрудника.

Поэтому кадровый план следующий: если посетители долго стоят в очереди при входе — нужно больше администраторов. Если они в ярости ломают друг другу лица, часами ожидая когда освободится единственная, уже до смерти усталая проститутка — увеличиваем штат проституток. Каждому типу сотрудников по своей комнате отдыха (в реальной жизни не самая лучшая стратегия, но, для примера, подходит идеально).

Ого, он такой… асинхронный?!

Что по процессам? Есть процесс регистрации посетителя и процесс его соития с проституткой, есть еще один… но то, что происходит в туалете, остается в туалете. Все они независимы друг от друга и других процессов, происходящих в борделе в этот момент (с точки зрения многопоточности эти процессы будут называться parallel). 

Огромный плюс регистрации в том, что этот процесс можно разделить на части, которыми одновременно будут заниматься разные сотрудники. Для получения финального результата нужно собрать воедино всё промежуточные результаты. Не пытайтесь повторить такое с сексом, так не работает. 

Попробуем разделить регистрацию. Для этого заводим службу безопасности и берем на работу пару студентов из меда, сажаем всех их в две каморки за ресепшеном и вешаем таблички на дверь, чтобы не перепутать. Служба безопасности будет проверять документы посетителей, а студенты — наличие различных заболеваний. Это разгрузит администратора, уменьшит задержки и увеличит пропускную способность. 

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

Точкой синхронизации этих трех параллельных процессов будет момент оплаты, когда администратор берет деньги с клиента, он должен быть на сто процентов уверен, что этот персонаж полностью безопасен. Обычно звонки из службы безопасности и лаборатории с результатами случаются раньше, чем наступает этот момент, поэтому проблем не возникает. В случае, если администратор не получил хотя бы один звонок, то он сидит в неловкой тишине и смотрит в потолок (примерно так и работают futures). Получив все недостающие ответы, администратор принимает решение по следующему шагу: либо он рассчитывает клиента и пропускает его дальше, либо вежливо предлагает покинуть заведение.

Что делать, если посетитель пошел в лабораторию, но не вернулся до того момента, когда администратор уже сбегал в службу безопасности? Ничего, ждать возвращения посетителя, без него продолжать регистрацию невозможно (wait-notify механизм).

Если бы всё было так просто, это знали бы все

Настало время метрик. Сейчас у каждого из администраторов есть свой личный блокнот к которому имеет доступ только он, и после регистрации каждого посетителя администратор записывает в блокнот статистику по клиентам (такие вещи называются thread local storage). В конце рабочего дня каждый администратор вырывает страницу из блокнота и отдает её охраннику, который всё это время молча сидел рядом со входом на своем протертом до поролона кресле, читая газету и, иногда, что-то комментируя себе под нос. Кстати, про него еще ходят слухи, что он побил того самого Али, когда тот был в своей лучшей форме. 

Работа охранника — не только охранять бордель от буйных клиентов, но еще и собирать со всех администраторов листочки со статистикой и записывать информацию по посетителям в толстенный журнал. Данный метод работает плохо: часть листочков теряется, калькулятора у охранника нет, он уже стар и косячит с цифрами. Статистику можно получить только за предыдущие сутки. Поэтому владелец борделя решил, что каждый администратор после того, как зарегистрировал посетителя, должен выйти в лобби и на доске перед входом прикрепить лист А4, на котором будет текущее количество посетителей (да, это самый обычный счетчик посетителей). Лист обязательно убрать в файл, и каждому посетителю будет видно, что наш бордель место популярное (это называется shared resource, а значит сейчас начнется самое интересное — concurrency). 

Ровно в полдень и ни секундой позже тот самый охранник должен сорвать листок и приклеить новый, на котором красуется цифра 0. Старое значение он, конечно же, записывает в свой журнал. 

Стоит сказать, что увеличение счетчика — сложный процесс, состоящий из трех этапов: вначале надо узнать текущее значение, дальше следует взять калькулятор или посчитать в уме новое значение, и в самом конце — записать новое значение туда, где каждый его увидит… на лист бумаги, прямо перед входом. Кстати, если бы существовали компьютеры, мало что бы изменилось, ведь этот процесс, внутри еще не изобретенных машин для просмотра котиков на ютубе, происходил бы абсолютно так же, только во много раз быстрее. 

Каждому администратору была дана четкая инструкция, как работать с этим счетчиком (она выше), но люди существа ленивые, поэтому они стали запоминать последние значения счетчика: зачем лишний раз ходить? Когда посетитель радостно поднимается наверх, чтобы воплотить свои самые сокровенные и грязные желания в жизнь, то администратор просто вспоминает текущее значение, прибавляет единицу, и радостно несет клеить бумажку на стену. Есть еще более ленивые персонажи, курильщики — они ходят обновлять счетчик не каждый раз, а только когда идут на перекур, по возвращению смотрят на число, записанное на бумажке, и запоминают его (вот как-то так и работает кэш процессора). 

Когда администратор работает один, проблем тут никаких нет: в конце дня всё сходится, если только он не убежал домой, забыв повесить на стене последнее запомненное значение. Но если администраторов несколько, все работают в спешке, подобная привычка сделает этот счетчик бессмысленным. 

Представим двух администраторов: один уже полчаса общается с довольно похотливым, но очень медленным старикашкой. Тот переспрашивает всё по три раза, по второму кругу рассказывает, чем он будет заниматься наверху, а потом долго отсчитывает сумму самыми мелкими монетами. Второму, можно сказать, повезло и вот уже третий посетитель молча выкладывает на стол нужную сумму денег и довольно быстро поднимается наверх.

После очередного молчуна наш “везунчик” (если его можно так назвать), закрывает глаза и вспоминает, что же он последний раз записывал. 23? Да, 23! Прибавляет к этому числу три — 26; при этом он этом хлопает себя по нагрудному карману — сигареты еще есть, отлично, пора перекурить. Записывает это число и радостно идет к доске вешать свой лист, после чего выходит на улицу любоваться рассветом. Он курит медленно, долгий, тяжелый вдох, задержать дыхание, быстрый выдох. Он делает это для того, чтобы растянуть удовольствие, чтобы никотин ударил в мозг и мир немного пошатнулся, да и кашель бьет по легким не так больно. Он знает, что до конца года не доживет, пагубная привычка добила его окончательно.

В это время первый наконец-то заканчивает общаться с дедушкой и вспоминает, что в последний раз, когда он ходил немного отлить, видел на стене число 23, поэтому он записывает 24 и идет вешать его на доску, ему плевать какое значение висит там. Второй, вернувшись с одного из своих последних перекуров, смотрит на доску. Там 24. Ему все равно что он там записал, главное запомнить — 24, 24, 24… и уходит обслуживать следующего клиента. 

    static int count = 0;
    private static void incrementCounter() {
        count++;
    }

    private static int getCounter() {
        return count;
    }

    public static void main(String[] args) {
        var administrators = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 10; i++) {
            administrators.execute(() -> {
                log.debug("администратор начал работу");
                for (int n = 0; n < 100; n++) {
                    doSomeAdminStuff();
                    incrementCounter();
                }
                log.debug("администратор закончил работу");

            });
        }

        awaitMorning();
        log.debug("а сколько у нас посетителей было (должна быть тысяча): {}", getCounter());
        // [main                ] - а сколько у нас посетителей было (должна быть тысяча): 762
    }

Математика не сходится, анализируем происходящее. Добавляем в инструкцию администраторов пункт на полный запрет что-либо там запоминать (это же volatile). По логике, это должно помочь решить проблему. Но уже несколько раз все те же два администратора попадали в следующую ситуацию: они почти одновременно заканчивают регистрировать посетителей, оба идут к доске, видят 11. Каждый возвращается за стойку, прибавляет единицу, оба записывают новое число на листок, у каждого получилось 12. Оба идут клеить свой листок на доску. (такая ситуация зовется race condition, к сожалению, она никуда не делась) 

		static volatile int count = 0;
    private static void incrementCounter() {
        count++;
    }

    private static int getCounter() {
        return count;
    }
    
    public static void main(String[] args) {
        var administrators = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 10; i++) {
            administrators.execute(() -> {
                log.debug("администратор начал работу");
                for (int n = 0; n < 100; n++) {
                    doSomeAdminStuff();
                    incrementCounter();
                }
                log.debug("администратор закончил работу");

            });
        }

        awaitMorning();
        log.debug("а сколько у нас посетителей было (должна быть тысяча): {}", getCounter());
        // [main                ] - а сколько у нас посетителей было (должна быть тысяча): 988
    }

Пора запретить этот бардак

Нельзя терять посетителей, пусть даже на бумаге. Решение приходит само собой: надо запретить администраторам одновременно обновлять этот счетчик (привет lock, mutex и критические секции). Хозяин борделя пишет новую инструкцию: когда администратор подходит к доске, и видит число, то первым делом он должен прикрепить лист со своим именем (это lock acquire или вход в критическую секцию), а уже потом делать все сложные вычисления и обновлять это значение. Если видит свое имя, то первый пункт можно пропустить. Если чужое, то он обязан стоять и ждать до тех пор, пока сотрудник, чье имя написано на листе, не вернется и не снимет лист со своим именем с доски (эта операция называется снятием блокировки — lock release или выходом из критической секции). 

При этом в инструкции не указано как именно сотрудники, которые столпились у доски, должны решать кто будет первым вешать свое имя на доску когда увидит число (это называется unfair lock). Кто быстрее — того и доска. В конечном счете они коллективно решили, что гораздо честнее будет выстраиваться в очередь перед доской (это уже fair lock).

    final static Lock lock = new ReentrantLock();
    static int count = 0;

    private static void incrementCounter() {
        try {
            lock.lock();
            count++;
        } catch (Exception ignore) {
        } finally {
            lock.unlock();
        }
    }

    private static int getCounter() {
        try {
            lock.lock();
            return count;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    // или можно использовать ключевое слово synchronized
    // private static synchronized void incrementCounter() {
    //    count++;
    // }

    // private static synchronized int getCounter() {
    //    return count;
    // }

    public static void main(String[] args) {
        var administrators = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 10; i++) {
            administrators.execute(() -> {
                log.debug("администратор начал работу");
                for (int n = 0; n < 100; n++) {
                    doSomeAdminStuff();
                    incrementCounter();
                }
                log.debug("администратор закончил работу");

            });
        }

        awaitMorning();
        log.debug("а сколько у нас посетителей было (должна быть тысяча): {}", getCounter());
        // [main                ] - а сколько у нас посетителей было (должна быть тысяча): 1000
    }

Сработало, цифры сходятся. Метрики считаются корректно, владелец наконец-то счастлив, разве что иногда высказывает свое недовольство, когда видит, что его сотрудники могут по 15-20 минут торчать у доски, ожидая своей очереди, а самого значения счетчика не видно. Но подход отлично работает, поэтому он был использован во всех возможных и невозможных местах. 

Как я уже говорил в самом начале, после общения с администратором посетитель получает одну или несколько карточек со случайным номером (анонимность в данном деле превыше всего). Их количество зависит от толщины кошелька и фантазий, которые даже своему психологу не рассказывают. А дальше он сам решает как будет проводить время: хоть с каждой по отдельности, хоть со всеми сразу. Надо вручить проститутке карточку, сказать в какую комнату идти, дальше либо последовать за ней, либо проделать ту же самую операцию еще раз.

Когда-нибудь это должно было случиться. В бордель заходят два моряка, один — старый колоритный морской волк, всё повидал, всех в этом борделе по многу раз пере-это-самое, и сегодня он решил, что надо взять сразу двух проституток: новенькую, молодую неопытную Алису, и вторую, прожжённую курву, жизнь повидавшую, пускай её имя будет Боб. Старику уже давно хотелось всё бросить и иметь нормальную семью. Второй моряк — молодой парень, для него наступила пора проб и ошибок и по совету администратора он обратил свое внимание на Боба и Алису. Как говориться, если и пробовать, то всё сразу.

Волчара первым делом отдал свою карточку Алисе, перекинулся парой фраз, отправил её в комнату, и пошел искать Боба. В этот самый момент второй моряк отдал свою карточку Бобу, так же отправил в комнату и пошел искать… Алису. Ходили они долго, искали тщательно, но каждый пришел сюда за своей целью, от которой отказываться никак не хотел. Паренек даже к администратору подходил несколько раз, спрашивал про Алису, но тот выдавал стандартную фразу: она занята, надо немного подождать, скоро освободится. Наступило утро, мелкий паренек весь на нервах, уже в шестой раз в туалете сбрасывает напряжение, а старый морской волк как присел на диван в холле, тихо посапывая, так и помер, не вставая с места (это пример типичного deadlock-а). Они так и не смогли за ночь найти, каждый свою вторую проститутку.

Ситуация не из приятных, скорая помощь, слезы, разбитые лица и прочая утренняя рутина. Деньги пришлось вернуть, услуга не была оказана и появился первый негативный отзыв в путеводителе. Одни потери, как финансовые, так и репутационные.

var alice = new Prostitute("Alice");
var bob = new Prostitute("Bob");

var oldSailor = new Thread(() -> {
    log.debug("пойти искать Алису");
    findProstitute();
    synchronized (alice) {
        log.debug("выбрать Алису");

        log.debug("пойти искать Боба");
        findProstitute();
        synchronized (bob) {
            log.debug("выбрать Боба");
            log.debug("Умотать в комнаду с двумя проститутками");
        }
    }
});

var yongSailor = new Thread(() -> {
    log.debug("пойти искать Боба");
    findProstitute();
    synchronized (bob) {
        log.debug("выбрать Боба");

        log.debug("пойти искать Алису");
        findProstitute();
        synchronized (alice) {
            log.debug("выбрать Алису");
            log.debug("Умотать в комнаду с двумя проститутками");
        }
    }
});

oldSailor.setName("Old Sailor");
oldSailor.start();

yongSailor.setName("Young Sailor");
yongSailor.start();

// [Young Sailor        ] - пойти искать Боба
// [Old Sailor          ] - пойти искать Алису
// [Young Sailor        ] - выбрать Боба
// [Old Sailor          ] - выбрать Алису
// [Young Sailor        ] - пойти искать Алису
// [Old Sailor          ] - пойти искать Боба

Повторения данного инцидента не хотелось и были приняты следующие решения:  всех сотрудниц записали в журнал по имени-фамилии, году рождения, отсортировали в алфавитном порядке и теперь посетитель, если он хочет утех сразу с несколькими проститутками, должен отдавать им карточки и отправлять в комнату только в этом, алфавитном порядке, и никак иначе (circular wait condition). Это первое. И второе: если проститутка уходит в комнату, а посетитель не приходит в течение 10 минут, она должна выйти из комнаты, мало ли что произошло. Номерок она обязана вернуть посетителю, чтобы он мог попробовать всю процедуру провести еще раз, с самого начала. Комментарий от владельца заведения был следующий: нечего других задерживать, если в данный момент все твои желания не могут быть исполнены.

Если бы первое условие было выполнено, то дедушка умер бы раньше, но гораздо более счастливым.

А другие способы существуют?

После ситуации с дедушкой экспериментировать на посетителях никто больше не решался. Администраторы — другое дело: им изменили правила подсчета, запоминать теперь не просто можно, а нужно. Больше никаких листов с именем. Теперь каждый администратор обязан запомнить последнее увиденное число на доске, сделать все необходимые вычисления за стойкой, а когда он возвращается обратно, то должен сравнить число, которое он запомнил с фактическим, на доске, которое, в свою очередь, к этому времени могло  и поменяться. Только если эти два числа совпадали, только тогда он мог повесить на стену листок с уже увеличенным значением (это compare and swap, либо compare and set). Если число, которое он запомнил не совпало с фактическим, он обязан, обязан начать все заново, вдруг ему повезет в следующий раз (именно так и работают lock-free алгоритмы).

var administrators = Executors.newFixedThreadPool(10);
var counter = new AtomicInteger();
for (int i = 0; i < 10; i++) {
    administrators.execute(() -> {
        log.debug("администратор начал работу");
        for (int n = 0; n < 100; n++) {
            doSomeAdminStuff();
            // неблокирующее обновление счетчика
            counter.incrementAndGet();
        }
        log.debug("администратор закончил работу");

    });
}

Эксперимент удался. В любой момент можно посмотреть текущее значение  счетчика, спонтанные очереди рядом с доской ушли в прошлое. Но появилась проблема. Возьмем пару администраторов и выделим среди них одного, который по два-три раза перепроверяет свои вычисления, всё у него четко, но парень медленный, да и отвлекаться любит часто. Подходит он к доске, чтобы повесить 32, но не может, там висит 33, запоминает его и уходит за стойку, достает калькулятор, считает два раза и еще один раз в уме, всегда получается 33, значит именно это он и должен записать на листочке. Записывает, идет к доске, а там уже 35. Да что такое?! Ладно, нужно второй раз сходить, запомнил 35, садится считать… но тут захотелось ему поссать, сбегал поссал, возвращается к доске с 36, а там висит 37 

После двадцатой итерации ему это надоедает: он уже три часа бегает от стойки к доске и обратно. Жрать хочет адски, в желудке дыра, бросить работу не может, счетчик обновить надо, а сколько он так будет бегать туда-сюда не представляет. прошлый раз до утра пробегал, пока все клиенты не ушли. Так и с голоду помереть можно (это типичный пример starvation). 

var administrators = Executors.newFixedThreadPool(10);
var counter = new AtomicInteger();

for (int i = 0; i < 9; i++) {
    administrators.execute(() -> {

        log.debug("администратор начал работу");
        for (int n = 0; n < 100; n++) {
            doSomeAdminStuff();

            while (true) {
                var current = counter.get();
                doItSlowly();
                var success = counter.compareAndSet(current, current + 1);
                if (success)
                    break;

            }
        }
        log.debug("администратор закончил работу");

    });
}

administrators.execute(() -> {
    int iHateMyJob = 0;
    log.debug("медленный администратор начал работу");
    for (int n = 0; n < 100; n++) {
        doSomeAdminStuff();

        int uhhh = 0;

        while (true) {
            var current = counter.get();
            doItExtremelySlowly();
            var success = counter.compareAndSet(current, current + 1);
            if (success)
                break;

            uhhh++;
        }

        iHateMyJob = Math.max(iHateMyJob, uhhh);
    }
    log.debug("медленный администратор закончил работу, уровень ненависти: {}", iHateMyJob);
});

// У меня на первом запуске получилось так:
// [pool-2-thread-10    ] - медленный администратор закончил работу, уровень ненависти: 467
// 467 попыток обновить значение, неплохо

И ладно, если бы это были проблемы только одного медленного администратора, бегает, тратит силы, плевать на него. Для работы борделя это не просто пустая трата времени, а увеличение задержек и снижение пропускной способности. Мы же стараемся сделать наоборот. Ради этого переоборудовали входную группу так, что к каждому администратору своя небольшая очередь, как в продуктовом магазине к кассам. Люди существа не слишком умные и, стоя в самом начале очереди, они начинают иногда тупить и задерживать всех остальных, очень долго выбирая к какому администратору пойти. Поэтому им приходится выбирать очередь в самом начале, в которой придется стоять до момента регистрации. Один из администраторов, вместо того, чтобы начать обслуживать следующего посетителя бегает туда-сюда с горящей жопой, остальные своих уже обслужили и начинают зазывать людей к себе, с конца очереди (такой подход называется work stealing). Но все равно нерасторопный сотрудник к утру часто получает негативный отзыв нецензурной бранью и хорошим таким хуком в красивое личико.

С таким подходом подсчета очень важно понимать, что в какой-то момент следует прекратить эту бессмысленную беготню (которая используется по умолчанию во всех неблокирующих алгоритмах и называется fast path) и перейти к решительным действиям. В нашем случае, после третьего неудачного раза, начинаем использовать старую добрую бумажку с именем (обратная сторона неблокирующих алгоритмов: вначале пробуем несколько раз пройтись по fast path, если не получается, переходим к slow path, который сложнее и дольше, но точно сработает с первого раза. В случае, если мы точно можем посчитать количество шагов за которое алгоритм синхронизации будет выполнен, он будет уже wait-free).

А ведь раньше я на железной дороге работала, Semapwhores 

Наконец-то закончили с этими скучными администраторами, пусть они себе и дальше спокойно бегают, циферки складывают, переходим к самому интересному — к проституткам.

В нашем борделе есть четкое правило: не больше четырех посетителей на одну стандартную комнату с огромной кроватью, при этом не уточняется кто с кем будет совокуплятся и будут ли вообще проститутки. А если берете огромный президентский люкс и штук пять проституток, то в нём уже можно будет устроить групповой заплыв всей команды небольшого рыболовного баркаса. 

Для реализации этого плана, рядом с каждой комнатой, в которой будет происходить непотребство, стоит охранник. Он контролирует количество входящих и выходящих людей, его кодовое имя — semapwhore (именно таким образом работает примитив синхронизации semaphore, в основе которого лежит счетчик с permit).

Как только матрос входит в комнату, охранник в своей голове проводит сложные математические вычисления по уменьшению данного счетчика. Если матрос худой, значит минус один, если огромный жирный потный мужик, значит считаем за двух (операция acquire(count), которая уменьшает количество пермитов). Когда кого-то во время пьяного угара выкинут в окно и он захочет вернуться в комнату через дверь, никакие уговоры не помогут, бедолагу посчитают еще раз. Выходить можно строго через дверь (тогда сработает обратная операция release(count), которая увеличит количество пермитов).

Также, матросу придется подождать, если в голове у охранника нулевое количество пермитов или их попросту недостаточно, матрос уж слишком жирный для прохода, а пермитов хватит только на худого. Уговаривать охранника можно только если цель — убить время, ожидая пока кто-нибудь выйдет из этой комнаты через дверь.

var semaphore = new Semaphore(4);

var sailors = Executors.newFixedThreadPool(10);
var counter = new AtomicInteger();
for (int i = 0; i < 10; i++) {
    sailors.execute(() -> {
        try {
            log.debug("Морячок пытается войти в комнату");
            semaphore.acquire();
            counter.incrementAndGet();
            log.debug("Морячок вошел в комнату, а там еще {} морячка", counter.get());
            SleepUtils.sleepQuietlyAround(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        finally {
            counter.decrementAndGet();
            semaphore.release();
            log.debug("Морячок вышел из комнаты, а там осталось {}", counter.get());
        }
    });
}

// [pool-2-thread-1     ] - Морячок пытается войти в комнату
// [pool-2-thread-3     ] - Морячок пытается войти в комнату
// [pool-2-thread-5     ] - Морячок пытается войти в комнату
// [pool-2-thread-6     ] - Морячок пытается войти в комнату
// [pool-2-thread-10    ] - Морячок пытается войти в комнату
// [pool-2-thread-7     ] - Морячок пытается войти в комнату
// [pool-2-thread-9     ] - Морячок пытается войти в комнату
// [pool-2-thread-4     ] - Морячок пытается войти в комнату
// [pool-2-thread-2     ] - Морячок пытается войти в комнату
// [pool-2-thread-8     ] - Морячок пытается войти в комнату
// [pool-2-thread-6     ] - Морячок вошел в комнату, а там еще 3 морячка
// [pool-2-thread-5     ] - Морячок вошел в комнату, а там еще 2 морячка
// [pool-2-thread-10    ] - Морячок вошел в комнату, а там еще 4 морячка
// [pool-2-thread-3     ] - Морячок вошел в комнату, а там еще 2 морячка
// [pool-2-thread-8     ] - Морячок вошел в комнату, а там еще 4 морячка
// [pool-2-thread-6     ] - Морячок вышел из комнаты, а там осталось 3
// [pool-2-thread-5     ] - Морячок вышел из комнаты, а там осталось 3
// [pool-2-thread-7     ] - Морячок вошел в комнату, а там еще 4 морячка
// [pool-2-thread-2     ] - Морячок вошел в комнату, а там еще 4 морячка
// [pool-2-thread-10    ] - Морячок вышел из комнаты, а там осталось 3
// [pool-2-thread-3     ] - Морячок вышел из комнаты, а там осталось 3
// [pool-2-thread-9     ] - Морячок вошел в комнату, а там еще 4 морячка
// [pool-2-thread-7     ] - Морячок вышел из комнаты, а там осталось 3
// [pool-2-thread-4     ] - Морячок вошел в комнату, а там еще 4 морячка
// [pool-2-thread-1     ] - Морячок вошел в комнату, а там еще 4 морячка
// [pool-2-thread-8     ] - Морячок вышел из комнаты, а там осталось 3
// [pool-2-thread-2     ] - Морячок вышел из комнаты, а там осталось 3
// [pool-2-thread-9     ] - Морячок вышел из комнаты, а там осталось 2
// [pool-2-thread-4     ] - Морячок вышел из комнаты, а там осталось 1
// [pool-2-thread-1     ] - Морячок вышел из комнаты, а там осталось 0

Представим ситуацию, в бордель забежала команда по гребле, только с международных соревнований, которые по стечению обстоятельств проходили в нашем городе. Работать синхронно и слаженно у них в крови — по другому победы не достичь никогда. Набрали проституток, каждому по одной, без всяких проблем зашли в люкс и начали заниматься сексом, каждый со своей. 

Данный процесс для них, как для команды, невероятно сложен: каждая пара находит место поудобнее, в этих царских хоромах этот процесс занимает время. Три пары оказались на кровати, одна на полу в прихожей, парочка на кресле уже разделась и готова к старту. Все ждут последнюю пару (await), которая пытается поудобнее устроиться на кухне. Как только все будут готовы, словно по выстрелу сигнального пистолета, они начинают заниматься сексом (так работает примитив синхронизации barrier, который создается со счетчиком, последний тред вызвавший метод await продолжает выполнение в каждом потоке). 

Их движения синхронны, охи и вздохи слышны в такт, но организм у каждого разный, поэтому длительность процесса варьируется, кто закончил — отдыхает, ждет всех остальных, мило беседуя со своей партнершей (обычно мы имеем дело с cyclicbarrier, который позволяет несколько раз использовать этот примитив синхронизации). Как только последний закончит, все начинают менять локацию, ждут окончания процесса. Вторую попытку начинают все также синхронно, после того как последняя парочка устроиться поудобнее.

var rowers = Executors.newFixedThreadPool(4);
var barrier = new CyclicBarrier(4);

for (int i = 0; i < 4; i++) {
    rowers.execute(() -> {
        try {
            log.debug("Пловец выбирает место");
            findPlace();

            log.debug("Пловец нашел место");
            barrier.await();

            log.debug("Пловец начинает заниматься сексом");
            doSex();

            log.debug("Пловец кончил, ждет остальных");
            barrier.await();

            log.debug("Решают, что надо еще раз, меняют позиции");
            findPlace();

            log.debug("Пловец нашел новое место");
            barrier.await();

            log.debug("Пловец начинает заниматься во второй раз");
            doSex();

            log.debug("Пловец кончил, ждет остальных");
            barrier.await();

            log.debug("Выходит из комнаты счастливым");
        } catch (Exception e) {
            e.printStackTrace();
        }
    });
}
        
// [pool-2-thread-4     ] - Пловец выбирает место
// [pool-2-thread-3     ] - Пловец выбирает место
// [pool-2-thread-2     ] - Пловец выбирает место
// [pool-2-thread-1     ] - Пловец выбирает место
// [pool-2-thread-1     ] - Пловец нашел место
// [pool-2-thread-3     ] - Пловец нашел место
// [pool-2-thread-2     ] - Пловец нашел место
// [pool-2-thread-4     ] - Пловец нашел место
// [pool-2-thread-4     ] - Пловец начинает заниматься сексом
// [pool-2-thread-1     ] - Пловец начинает заниматься сексом
// [pool-2-thread-3     ] - Пловец начинает заниматься сексом
// [pool-2-thread-2     ] - Пловец начинает заниматься сексом
// [pool-2-thread-3     ] - Пловец кончил, ждет остальных
// [pool-2-thread-4     ] - Пловец кончил, ждет остальных
// [pool-2-thread-2     ] - Пловец кончил, ждет остальных
// [pool-2-thread-1     ] - Пловец кончил, ждет остальных
// [pool-2-thread-1     ] - Решают, что надо еще раз, меняют позиции
// [pool-2-thread-3     ] - Решают, что надо еще раз, меняют позиции
// [pool-2-thread-4     ] - Решают, что надо еще раз, меняют позиции
// [pool-2-thread-2     ] - Решают, что надо еще раз, меняют позиции
// [pool-2-thread-4     ] - Пловец нашел новое место
// [pool-2-thread-2     ] - Пловец нашел новое место
// [pool-2-thread-3     ] - Пловец нашел новое место
// [pool-2-thread-1     ] - Пловец нашел новое место
// [pool-2-thread-1     ] - Пловец начинает заниматься во второй раз
// [pool-2-thread-4     ] - Пловец начинает заниматься во второй раз
// [pool-2-thread-2     ] - Пловец начинает заниматься во второй раз
// [pool-2-thread-3     ] - Пловец начинает заниматься во второй раз
// [pool-2-thread-3     ] - Пловец кончил, ждет остальных
// [pool-2-thread-4     ] - Пловец кончил, ждет остальных
// [pool-2-thread-2     ] - Пловец кончил, ждет остальных
// [pool-2-thread-1     ] - Пловец кончил, ждет остальных
// [pool-2-thread-1     ] - Выходит из комнаты счастливым
// [pool-2-thread-3     ] - Выходит из комнаты счастливым
// [pool-2-thread-4     ] - Выходит из комнаты счастливым
// [pool-2-thread-2     ] - Выходит из комнаты счастливым

Представим еще более дикую ситуацию (в которой будет участвовать примитив синхронизации countdownlatch, он также создается со счетчиком): день рожденья у одного из участников квартета, который исполняет в жанре А-капелла. Они сняли пять проституток и заготовили огромный торт, вручили самой страшной проститутке на этой части планеты, с четкой инструкцией: стоять за дверью и слушать (висеть на методе await, дожидаясь пока счётчик не станет равен нулю), как только четвертый раз прозвучит нота ля первой октавы, это фишка данного коллектива, издавать именно этот звук при достижении оргазма (в этот момент будет вызван метод countdown и значение счетчика уменьшится на единицу), войти в комнату с тортом и поздравить именинника. 

План был хорош! После четвертой протяжной ноты ля, она врывается в комнату и видит как именинник, в окружении трех обессиленных коллег, в поте лица совершает возвратно-поступательные движения, чтобы издать этот магический звук. Полный провал. Объяснение простое — кто-то успел кончить два раза.

Следует всегда быть осторожным с countdownlatch, условие, по которому поток, висящий на методе await продолжит выполнение — внутренний счетчик, значение которого стало равным нулю, кто и сколько раз вызовет метод countdown, не имеет значения. 

var singers = Executors.newFixedThreadPool(4);
var prostitute = Executors.newFixedThreadPool(1);
var latch = new CountDownLatch(4);

for (int i = 0; i < 3; i++) {
    singers.execute(() -> {
        log.debug("Певец начинает заниматься сексом");
        doSex();

        log.debug("Певец закончил");
        latch.countDown();

        log.debug("Певец решает еще разок");
        doSex();

        log.debug("Певец закончил еще раз");
        latch.countDown();
    });
}

singers.execute(() -> {
    log.debug("Именнинник начинает заниматься сексом");
    doSexSlowly();

    log.debug("Именнинник закончил");
    latch.countDown();
});

prostitute.execute(() -> {
    try {
        log.debug("Проститутка ждет задверью пока все закончат...");
        latch.await();

        log.debug("Простутутка входит в комнату с тортом");
    } catch (Exception e) {

    }
});

// [pool-2-thread-1     ] - Певец начинает заниматься сексом
// [pool-2-thread-3     ] - Певец начинает заниматься сексом
// [pool-2-thread-2     ] - Певец начинает заниматься сексом
// [pool-2-thread-4     ] - Именнинник начинает заниматься сексом
// [pool-3-thread-1     ] - Проститутка ждет задверью пока все закончат...
// [pool-2-thread-3     ] - Певец закончил
// [pool-2-thread-3     ] - Певец решает еще разок
// [pool-2-thread-1     ] - Певец закончил
// [pool-2-thread-1     ] - Певец решает еще разок
// [pool-2-thread-2     ] - Певец закончил
// [pool-2-thread-2     ] - Певец решает еще разок
// [pool-2-thread-3     ] - Певец закончил еще раз
// [pool-3-thread-1     ] - Простутутка входит в комнату с тортом
// [pool-2-thread-1     ] - Певец закончил еще раз
// [pool-2-thread-4     ] - Именнинник закончил
// [pool-2-thread-2     ] - Певец закончил еще раз      

По этическим соображениям, в данной статье будет опущено описание такого потока синхронизации как rendezvous (и нет, это не магазин с туфельками), хотя на практике, в нашем борделе, это один из самых часто используемых примитивов. На техническом языке он работает следующим образом: первый поток, приходя в точку рандеву, вызывает метод exchange(object) и ожидает, пока второй поток не сделает тоже самое. Дальше они оба продолжают работу. 

Как с этим жить дальше

На сегодня всё, рабочий день подходит к концу, администраторы устало зевают, проститутки, не спеша, собираются домой, а охранник, который всё это время тихо сидел в углу и читал газету, встает со своего потертого кресла и идет обнулять счетчик посетителей. 

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

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

  • Сравнивать не с чем как пишется
  • Сравни песню мусоргского с пьесами нянина сказка чайковского и сказочка прокофьева что их объединяет
  • Сравни сказку о мертвой царевне и семи богатырях и белоснежка и семь гномов 4 класс
  • Сравни сказку и басню используя опорные слова 3 класс
  • Сравни с тем как заканчиваются народные сказки которые ты прочитал в этом году