erid: 2RanyoKCft4
CodeFest — это ежегодная тёплая ламповая айтишная конференция, на которую слетаются русскоговорящие айтишники с разных уголков страны, чтобы встретиться с коллегами, поделиться новостями и обсудить последние тенденции в мире разработки.
Ключевые направления программы: Backend, Frontend, Management, QA, Data Science, Mobile, Design, Web 3, System Аnalysis, а также дискуссионный народный поток Kvartirniki и вдохновляющие Keynote выступления от айти-звёзд.
Изюминка CodeFest — неформальное общение, которого много, которое невероятно дружелюбное, и зачином для которого служат те самые выступления в ключевых секциях. Начали с доклада в зале — закончили спонтанным митапом в холле.
Присоединяйтесь к невероятной атмосфере конференции:
■ 25-26 мая, Новосибирск, Экспоцентр.
■ 1800 участников на одной площадке.
■ Участие офлайн и онлайн.
■ Более 120 докладов.
■ Насыщенная программа от партнёров конференции.
Приезжайте командой, участвуйте лично.
Регистрация 👉 https://l.codefest.ru/javatasks
Реклама. АО "Тинькофф Банк", ИНН 7710140679, лицензия ЦБ РФ № 2673
CodeFest — это ежегодная тёплая ламповая айтишная конференция, на которую слетаются русскоговорящие айтишники с разных уголков страны, чтобы встретиться с коллегами, поделиться новостями и обсудить последние тенденции в мире разработки.
Ключевые направления программы: Backend, Frontend, Management, QA, Data Science, Mobile, Design, Web 3, System Аnalysis, а также дискуссионный народный поток Kvartirniki и вдохновляющие Keynote выступления от айти-звёзд.
Изюминка CodeFest — неформальное общение, которого много, которое невероятно дружелюбное, и зачином для которого служат те самые выступления в ключевых секциях. Начали с доклада в зале — закончили спонтанным митапом в холле.
Присоединяйтесь к невероятной атмосфере конференции:
■ 25-26 мая, Новосибирск, Экспоцентр.
■ 1800 участников на одной площадке.
■ Участие офлайн и онлайн.
■ Более 120 докладов.
■ Насыщенная программа от партнёров конференции.
Приезжайте командой, участвуйте лично.
Регистрация 👉 https://l.codefest.ru/javatasks
Реклама. АО "Тинькофф Банк", ИНН 7710140679, лицензия ЦБ РФ № 2673
👍5🔥2
Как разбить строку на слова?
StringTokenizer – специально предназначенный для этого класс стандартной библиотеки Java. Ему нужно задать разделители, по ним строка будет разделена на «токены». Это устаревший класс, он остается в библиотеке только для обратной совместимости.
Вместо него рекомендуется использовать метод String.split(). Метод принимает строку с регулярным выражением, и опциональный лимит токенов. Реализация особенно оптимизирована для односимвольного разделителя. Но следует помнить, что даже если символ один, это всё ещё регулярное выражение – спецсимвол должен экранироваться.
Другой подходящий метод – Pattern.split(). Он, наоборот, вызывается у регулярного выражения, а принимает целевую строку. В этот же метод делегируется и выполнение String.split(). Этот способ предпочтительнее, когда в регулярном выражении больше одного символа, а скомпилированный паттерн применяется повторно.
StringTokenizer – специально предназначенный для этого класс стандартной библиотеки Java. Ему нужно задать разделители, по ним строка будет разделена на «токены». Это устаревший класс, он остается в библиотеке только для обратной совместимости.
Вместо него рекомендуется использовать метод String.split(). Метод принимает строку с регулярным выражением, и опциональный лимит токенов. Реализация особенно оптимизирована для односимвольного разделителя. Но следует помнить, что даже если символ один, это всё ещё регулярное выражение – спецсимвол должен экранироваться.
Другой подходящий метод – Pattern.split(). Он, наоборот, вызывается у регулярного выражения, а принимает целевую строку. В этот же метод делегируется и выполнение String.split(). Этот способ предпочтительнее, когда в регулярном выражении больше одного символа, а скомпилированный паттерн применяется повторно.
👍16❤2🔥2
Перегрузка — очень мощная техника для случаев, когда нужно одинаковое имя метода с разными параметрами. Вместо того, чтобы дублировать имя метода и добавлять беспорядок в ваш код, вы можете просто перегрузить его. Это позволяет сохранять код чистым, а также снижает риск того, что дублирующие методы сломают часть системы.
Как это провернуть? Расскажет опытный эксперт на открытом практическом уроке от OTUS! Встречаемся 26 апреля в 20:00 мск в преддверии старта курса «Углубленное изучение языка Java».
Все участники вебинара получат специальную цену на обучение и персональную консультацию от менеджеров OTUS!
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🔥1
Как прочитать InputStream в строку?
Обычно строковые данные извне попадают в программу именно в виде потока. Потоком читаются файлы, сетевые данные из сокета, пользовательский ввод. Если есть такая возможность, лучше избегать сохранения потоковых данных в память, и обрабатывать их также в потоке. Например, когда из большого xml-файла необходимо достать один определенный элемент, имеет смысл выбрать потоковый xml-парсер.
В общем виде все решения выглядят так. Заводится буфер – массив символов. Поток направляется в этот буфер. По заполнению данные из массива присоединяются в хвост строки-результата.
Простой способ – использовать трюк со сканером. Вообще класс Scanner читает из потока подстроки, разделенные указанным символом. Когда нужно прочитать всю строку сразу, в качестве разделителя устанавливается "\\A" – спецсимвол «начало строки». Это решение просто в реализации, но имеет проблемы. Размер внутреннего буфера фиксирован (1024 символа), а логика поиска разделителя плохо влияет на производительность.
Хорошее решение для продакшна – читать в собственный массив-буфер непосредственно методом InputStream.read, либо обернув поток в InputStreamReader. Данные из буфера затем переправляются в строку через StringBuilder или ByteArrayOutputStream. За готовой реализацией можно обратиться в библиотеки Apache Commons IO и Google Guava. Полный код реализации и сравнение производительности описаны на stackoverflow.
На интервью этот вопрос часто возникает как часть практической задачи, для консольного ввода-вывода. Поэтому, если вы идете на собеседование со своим компьютером, и неуверенно владеете классами работы с потоками, стоит заранее подготовить шпаргалку с кодом.
Обычно строковые данные извне попадают в программу именно в виде потока. Потоком читаются файлы, сетевые данные из сокета, пользовательский ввод. Если есть такая возможность, лучше избегать сохранения потоковых данных в память, и обрабатывать их также в потоке. Например, когда из большого xml-файла необходимо достать один определенный элемент, имеет смысл выбрать потоковый xml-парсер.
В общем виде все решения выглядят так. Заводится буфер – массив символов. Поток направляется в этот буфер. По заполнению данные из массива присоединяются в хвост строки-результата.
Простой способ – использовать трюк со сканером. Вообще класс Scanner читает из потока подстроки, разделенные указанным символом. Когда нужно прочитать всю строку сразу, в качестве разделителя устанавливается "\\A" – спецсимвол «начало строки». Это решение просто в реализации, но имеет проблемы. Размер внутреннего буфера фиксирован (1024 символа), а логика поиска разделителя плохо влияет на производительность.
Хорошее решение для продакшна – читать в собственный массив-буфер непосредственно методом InputStream.read, либо обернув поток в InputStreamReader. Данные из буфера затем переправляются в строку через StringBuilder или ByteArrayOutputStream. За готовой реализацией можно обратиться в библиотеки Apache Commons IO и Google Guava. Полный код реализации и сравнение производительности описаны на stackoverflow.
На интервью этот вопрос часто возникает как часть практической задачи, для консольного ввода-вывода. Поэтому, если вы идете на собеседование со своим компьютером, и неуверенно владеете классами работы с потоками, стоит заранее подготовить шпаргалку с кодом.
👍19🔥1
Сертификат по кибербезопасности на новом курсе для старших разработчиков Java
🚀 12 мая мы запускаем юбилейный поток курса Senior Java Developer с новой программой.
Что изменилось? Мы усилили курс новым модулем по кибербезопасности.
❓Зачем Java-разработчику разбираться в кибербезопасности? Логичный вопрос. И вот что мы ответим: наши партнеры провели опрос: на что бизнес обращает внимание при выборе платформы корпоративного банкинга. 100% ответов — защищенный доступ к финансам в личном кабинете с использованием двухфакторной аутентификации. Умеешь защищать данные при разработке — продукт еще больше ценят на рынке. Все просто!
✅ Итак, что тебя ждет на курсе:
- Развертывание приложений с помощью DevSecOps
- Моделирование схемы контроля доступа для систем и приложений
- Углубленное изучение Java Concurrency и Spring
- Архитектура — паттерны проектирования, Docker, Kubernetes
- Двойная сертификация по Java и кибербезопасности
💥И это лишь часть программы нового курса. Специально для тебя открыли 5 мест с индивидуальным менторским сопровождением. После прохождения шести образовательных модулей мы поможем тебе с трудоустройством у наших партнеров: Сбера, СДЭК и ЦБ.
➡️ Почитать подробности и оставить заявку можно здесь: https://clck.ru/3AJExx
Реклама. ООО "Платформа непрерывного обучения" ИНН 7839405924
erid: 2VtzqvhKyV2
🚀 12 мая мы запускаем юбилейный поток курса Senior Java Developer с новой программой.
Что изменилось? Мы усилили курс новым модулем по кибербезопасности.
❓Зачем Java-разработчику разбираться в кибербезопасности? Логичный вопрос. И вот что мы ответим: наши партнеры провели опрос: на что бизнес обращает внимание при выборе платформы корпоративного банкинга. 100% ответов — защищенный доступ к финансам в личном кабинете с использованием двухфакторной аутентификации. Умеешь защищать данные при разработке — продукт еще больше ценят на рынке. Все просто!
✅ Итак, что тебя ждет на курсе:
- Развертывание приложений с помощью DevSecOps
- Моделирование схемы контроля доступа для систем и приложений
- Углубленное изучение Java Concurrency и Spring
- Архитектура — паттерны проектирования, Docker, Kubernetes
- Двойная сертификация по Java и кибербезопасности
💥И это лишь часть программы нового курса. Специально для тебя открыли 5 мест с индивидуальным менторским сопровождением. После прохождения шести образовательных модулей мы поможем тебе с трудоустройством у наших партнеров: Сбера, СДЭК и ЦБ.
➡️ Почитать подробности и оставить заявку можно здесь: https://clck.ru/3AJExx
Реклама. ООО "Платформа непрерывного обучения" ИНН 7839405924
erid: 2VtzqvhKyV2
🔥5👍2
Что такое synchronized?
Можно применять как модификатор метода, и как самостоятельный оператор с блоком кода. Выполняет код при захваченном мониторе объекта. В виде оператора объект указывается явно. В виде модификатора нестатического метода используется this, статического – .class текущего класса.
Один из основных инструментов обеспечения потокобезопасности. Одновременно выполняется не более одного блока synchronized на одном и том же объекте. Такая блокировка называется intrinsic lock или monitor lock, подробно рассматривается в Java Concurrency in Practice 2.3.1.
Блок synchronized также необходим для использования методов wait, notify, notifyAll.
Можно применять как модификатор метода, и как самостоятельный оператор с блоком кода. Выполняет код при захваченном мониторе объекта. В виде оператора объект указывается явно. В виде модификатора нестатического метода используется this, статического – .class текущего класса.
Один из основных инструментов обеспечения потокобезопасности. Одновременно выполняется не более одного блока synchronized на одном и том же объекте. Такая блокировка называется intrinsic lock или monitor lock, подробно рассматривается в Java Concurrency in Practice 2.3.1.
Блок synchronized также необходим для использования методов wait, notify, notifyAll.
👍12❤🔥1🔥1
В мае стартует новая программа «Java разработчик. Уровень Специалист».
Обучение проходит в мини-группе с преподавателем и живой практикой. Часть материалов — для самообучения.
Программа включает в себя:
📌 Применение ООП и функциональной парадигмы,
📌 Spring Framework,
📌 работу с БД,
📌 архитектуру REST,
📌 вспомогательные инструменты Java-разработчика,
📌 продвинутые аспекты применения Java,
📌 стандартную библиотеку Java II.
👉 Узнать подробнее 👈
Бонусы:
✔️ всем, кто запишется на программу до 17 мая, предоставляем бесплатный доступ к первым 5 урокам на 3 дня
✔️ подготовка к сдаче Java-сертификации и скидка 50% на ее прохождение
✔️ бесплатный курс «Разработка на Java и Spring с помощью Chat GPT: от составления ТЗ до модульного тестирования»
Реклама. АНО ДПО "УЦ ИБС". ИНН 7713388004. erid: LjN8K6Ntz
Обучение проходит в мини-группе с преподавателем и живой практикой. Часть материалов — для самообучения.
Программа включает в себя:
📌 Применение ООП и функциональной парадигмы,
📌 Spring Framework,
📌 работу с БД,
📌 архитектуру REST,
📌 вспомогательные инструменты Java-разработчика,
📌 продвинутые аспекты применения Java,
📌 стандартную библиотеку Java II.
👉 Узнать подробнее 👈
Бонусы:
✔️ всем, кто запишется на программу до 17 мая, предоставляем бесплатный доступ к первым 5 урокам на 3 дня
✔️ подготовка к сдаче Java-сертификации и скидка 50% на ее прохождение
✔️ бесплатный курс «Разработка на Java и Spring с помощью Chat GPT: от составления ТЗ до модульного тестирования»
Реклама. АНО ДПО "УЦ ИБС". ИНН 7713388004. erid: LjN8K6Ntz
🔥6🎉1
Что делает volatile?
volatile – ключевое слово для работы с многопоточностью. Не то же самое, что volatile в C++, не обязано делать что-либо с кэшем процессора. Оказывает на поле объекта ровно два эффекта.
Во-первых, чтение/запись такого поля становятся атомарными. Это применение актуально только для long и double, и не на всех платформах. Для остальных типов полей это верно и так.
Второй и самый интересный эффект – пара событий запись-чтение для такого поля являются synchronization actions. Значит, между ними существует отношение happens-before. Это значит, что существует гарантия, что произошедшее в памяти до записи будет видно после чтения. То есть будут успешно прочитаны значения, записанные в другие переменные.
Для полного понимания темы рекомендуется к просмотру доклад Алексея Шипилёва и документация. Лучше всего эффект volatile иллюстрирует задача из этого доклада, которую часто и дают в качестве этого вопроса. Вопрос – что выведет данный код:
Этот эффект используется для получения простой и дешевой адаптации программы к многопоточной среде без использования сложных и ошибкоопасных техник блокировок и синхронизаций.
volatile – ключевое слово для работы с многопоточностью. Не то же самое, что volatile в C++, не обязано делать что-либо с кэшем процессора. Оказывает на поле объекта ровно два эффекта.
Во-первых, чтение/запись такого поля становятся атомарными. Это применение актуально только для long и double, и не на всех платформах. Для остальных типов полей это верно и так.
Второй и самый интересный эффект – пара событий запись-чтение для такого поля являются synchronization actions. Значит, между ними существует отношение happens-before. Это значит, что существует гарантия, что произошедшее в памяти до записи будет видно после чтения. То есть будут успешно прочитаны значения, записанные в другие переменные.
Для полного понимания темы рекомендуется к просмотру доклад Алексея Шипилёва и документация. Лучше всего эффект volatile иллюстрирует задача из этого доклада, которую часто и дают в качестве этого вопроса. Вопрос – что выведет данный код:
int a; int b;Трюк в том, что помимо очевидных 21 (поток 2 отработал после 1), 00 (поток 2 отработал до 1, переменные еще не инициализированы) и 01 (поток 2 сработал между записями), может быть и неожиданные 20. Дело в том, что для операторов одного потока действует program order, он гарантирует хотя бы видимость правильной последовательности операций. Между потоками необходим «мост» из happens-before. Его даст применение модификатора volatile к переменной b, неожиданный результат 20 будет исключен.
// thread 1:
a = 1;
b = 2;
// thread 2:
System.out.print(b);
System.out.print(a);
Этот эффект используется для получения простой и дешевой адаптации программы к многопоточной среде без использования сложных и ошибкоопасных техник блокировок и синхронизаций.
👍15❤4🔥1
❓ Как наладить взаимодействие Kafka и Clickhouse?
Apache Kafka и ClickHouse — два популярных инструмента обработки и анализа данных, которые так нужны дата-инженерам и разработчикам.
👉 На открытом практическом уроке от OTUS опытный эксперт расскажет, как превратить две этих технологии в эффективный тандем!
— Рассмотрим Apache Kafka. Познакомимся с ClickHouse.
— Узнаем, как организовать загрузку данных из Kafka в ClickHouse.
— Ответим на все возникающие вопросы.
Встречаемся 8 мая в 20:00 мск в преддверии старта курса «Apache Kafka».
⚡️ Регистрируйтесь прямо сейчас, чтобы не пропустить бесплатный урок: https://vk.cc/cwuAT6
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
Apache Kafka и ClickHouse — два популярных инструмента обработки и анализа данных, которые так нужны дата-инженерам и разработчикам.
👉 На открытом практическом уроке от OTUS опытный эксперт расскажет, как превратить две этих технологии в эффективный тандем!
— Рассмотрим Apache Kafka. Познакомимся с ClickHouse.
— Узнаем, как организовать загрузку данных из Kafka в ClickHouse.
— Ответим на все возникающие вопросы.
Встречаемся 8 мая в 20:00 мск в преддверии старта курса «Apache Kafka».
⚡️ Регистрируйтесь прямо сейчас, чтобы не пропустить бесплатный урок: https://vk.cc/cwuAT6
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
🔥5🎉2👍1
Какими коллекциями пользоваться в многопоточной среде?
Первый вариант – превратить в синхронизированную обычную коллекцию, вызвав соответствующий ее типу метод Collections.synchronized*(). Самый общий и самый примитивный способ, создает обертку с синхронизацией всех операций с помощью synchronized.
Если работа с коллекцией состоит в основном из чтения, лучшая в плане производительности альтернатива – CopyOnWriteArrayList, и содержащий его в реализации CopyOnWriteArraySet. Потокобезопасность достигается копированием внутреннего массива при любой модификации, оригинальный массив остается immutable. Program order достигается модификатором volatile на внутреннем массиве.
Третий вариант – использование Concurrent-коллекций:
🔘 Неблокирующие хэш-таблицы ConcurrentSkipListMap, ConcurrentHashMap и ConcurrentSkipListSet (хэш-таблица в основе реализации)
🔘 Неблокирующие очереди ConcurrentLinkedQueue и ConcurrentLinkedDeque
🔘 Большой набор различных блокирующих очередей
Первый вариант – превратить в синхронизированную обычную коллекцию, вызвав соответствующий ее типу метод Collections.synchronized*(). Самый общий и самый примитивный способ, создает обертку с синхронизацией всех операций с помощью synchronized.
Если работа с коллекцией состоит в основном из чтения, лучшая в плане производительности альтернатива – CopyOnWriteArrayList, и содержащий его в реализации CopyOnWriteArraySet. Потокобезопасность достигается копированием внутреннего массива при любой модификации, оригинальный массив остается immutable. Program order достигается модификатором volatile на внутреннем массиве.
Третий вариант – использование Concurrent-коллекций:
🔘 Неблокирующие хэш-таблицы ConcurrentSkipListMap, ConcurrentHashMap и ConcurrentSkipListSet (хэш-таблица в основе реализации)
🔘 Неблокирующие очереди ConcurrentLinkedQueue и ConcurrentLinkedDeque
🔘 Большой набор различных блокирующих очередей
👍9❤1🥰1😁1
Проверь насколько хорошо ты знаешь Java и готов освоить Spring!
Ответишь — пройдешь на продвинутый курс "Разработчик на Spring Framework" от OTUS по специальной цене.
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1😁1
Как в лямбде изменить внешнюю локальную переменную?
Это нельзя сделать в лоб. Такой код не скомпилируется, потому что захваченная локальная переменная обязана быть effectively final. Такое требование исходит из следующих причин.
Локальная переменная хранится на стеке, а значит время ее жизни в отличие от долгоживущих элементов хипа ограничено скоупом и текущим потоком. Но экземпляр лямбды, захвативший эту переменную, мог бы быть передан наружу и использован для доступа к этой переменной из другого потока и после выхода из метода.
Эта проблема решается тем, что в лямбду копируется значение локальной переменной. Такая копия живет независимо, возможно дольше оригинала. Но это решение приведет к сложному поведению из-за возможности работы с неактуальным значением – копия и оригинал станут двумя разными переменными. Поэтому значение должно быть вечно актуально – неизменяемо.
Поля экземпляра менять можно, потому что захваченной переменной в этом случае выступает effectively final значение this.
Если локальную переменную всё же хочется изменить, решение очевидно – поместить её в кучу. Для этого нужно использовать любого рода обертку: одноэлементный массив, объект-atomic, специально созданный класс с этой переменной как полем.
Хак с оберткой решает проблему времени жизни и даёт коду скомпилироваться, но возвращает проблему сложности поведения. Если среда многопоточная, то вероятно порядок операций с этой переменной придется синхронизировать вручную.
Это нельзя сделать в лоб. Такой код не скомпилируется, потому что захваченная локальная переменная обязана быть effectively final. Такое требование исходит из следующих причин.
Локальная переменная хранится на стеке, а значит время ее жизни в отличие от долгоживущих элементов хипа ограничено скоупом и текущим потоком. Но экземпляр лямбды, захвативший эту переменную, мог бы быть передан наружу и использован для доступа к этой переменной из другого потока и после выхода из метода.
Эта проблема решается тем, что в лямбду копируется значение локальной переменной. Такая копия живет независимо, возможно дольше оригинала. Но это решение приведет к сложному поведению из-за возможности работы с неактуальным значением – копия и оригинал станут двумя разными переменными. Поэтому значение должно быть вечно актуально – неизменяемо.
Поля экземпляра менять можно, потому что захваченной переменной в этом случае выступает effectively final значение this.
Если локальную переменную всё же хочется изменить, решение очевидно – поместить её в кучу. Для этого нужно использовать любого рода обертку: одноэлементный массив, объект-atomic, специально созданный класс с этой переменной как полем.
Хак с оберткой решает проблему времени жизни и даёт коду скомпилироваться, но возвращает проблему сложности поведения. Если среда многопоточная, то вероятно порядок операций с этой переменной придется синхронизировать вручную.
👍16❤5🌭2👌1
Erid: 2VtzqxkzjSZ
👋 Тебя приглашают в Росбанк IT Team
Привет, мы ИТ-команда Росбанка! Познакомься со стеком наших Java-разработчиков. Есть что-то незнакомое? Это нестрашно — всему научим!
А пока подпишись на телеграм-канал Росбанк IT Team. Там мы:
🔸делимся экспертизой, рассказываем о последних трендах и раскрываем секреты разработки продуктов;
🔸знакомим с нашей корпоративной культурой;
🔸публикуем актуальные вакансии с полной удаленкой: у нас есть предложения, от которых ты не сможешь отказаться.
👉 Подпишись на Росбанк IT Team и стань частью нашего крутого сообщества!
Реклама. ПАО "Росбанк" ИНН 7730060164
👋 Тебя приглашают в Росбанк IT Team
Привет, мы ИТ-команда Росбанка! Познакомься со стеком наших Java-разработчиков. Есть что-то незнакомое? Это нестрашно — всему научим!
А пока подпишись на телеграм-канал Росбанк IT Team. Там мы:
🔸делимся экспертизой, рассказываем о последних трендах и раскрываем секреты разработки продуктов;
🔸знакомим с нашей корпоративной культурой;
🔸публикуем актуальные вакансии с полной удаленкой: у нас есть предложения, от которых ты не сможешь отказаться.
👉 Подпишись на Росбанк IT Team и стань частью нашего крутого сообщества!
Реклама. ПАО "Росбанк" ИНН 7730060164
👍5❤2🔥1
Как получить гарантированный дедлок?
Сначала поговорим о том, что это такое. Deadlock – это взаимная блокировка, ситуация, когда два или более потока «наступают друг-другу на хвост» – зависают в вечном ожидании ресурсов, захваченных друг другом.
Livelock – похожая проблема, с тем лишь отличием, что потоки не останавливаются, а вместо этого зацикливаются, выполняя одни и те же бесполезные действия, ходят по кругу.
Стандартный подход к обеспечению гарантии защиты от дедлока – установка строгого порядка взятия блокировок. Если для мониторов A и B соблюдается всеобщий порядок захвата AB (и соответственно отпускания BA), то ни с одним потоком не случится попасть на ожидание B, успешно при этом захватив A.
Из этого можно догадаться, простой способ гарантировать возможность дедлока – явно нарушить это условие.
Нарушение условия даст дедлок «скорее всего когда-нибудь». Чтобы получить его точно и с первого раза, нужно гарантировать, что оба потока окажутся на этапе между захватами одного и другого ресурса в одно время. Это можно сделать множеством способов, в примере ниже использован CyclicBarrier.
Сначала поговорим о том, что это такое. Deadlock – это взаимная блокировка, ситуация, когда два или более потока «наступают друг-другу на хвост» – зависают в вечном ожидании ресурсов, захваченных друг другом.
Livelock – похожая проблема, с тем лишь отличием, что потоки не останавливаются, а вместо этого зацикливаются, выполняя одни и те же бесполезные действия, ходят по кругу.
Стандартный подход к обеспечению гарантии защиты от дедлока – установка строгого порядка взятия блокировок. Если для мониторов A и B соблюдается всеобщий порядок захвата AB (и соответственно отпускания BA), то ни с одним потоком не случится попасть на ожидание B, успешно при этом захватив A.
Из этого можно догадаться, простой способ гарантировать возможность дедлока – явно нарушить это условие.
Нарушение условия даст дедлок «скорее всего когда-нибудь». Чтобы получить его точно и с первого раза, нужно гарантировать, что оба потока окажутся на этапе между захватами одного и другого ресурса в одно время. Это можно сделать множеством способов, в примере ниже использован CyclicBarrier.
👍10🔥3
Как устроены атомики?
Начнем с того, что такое атомики и зачем нужны. Atomic* – семейство классов из java.util.concurrent. Они предоставляют набор атомарных операций для соответствующих типов. Например с помощью методов getAndIncrement/incrementAndGet класса AtomicInteger можно делать неатомарный в обычных условиях инкремент (i++).
Условно можно разделить подходы реализации большинства atomic-методов на две группы: compare-and-set и set-and-get.
Методы категории compare-and-set принимают старое значение и новое. Если переданное старое значение совпало с текущим, устанавливается новое. Обычно делегируют вызов в методы класса Unsafe, которые заменяются нативными реализациями виртуальной машины. Виртуальная машина в большинстве случаев использует атомарную операцию процессора compare-and-swap (CAS). Поэтому атомики обычно более эффективны чем стандартная дорогостоящая блокировка.
В случае set-and-get старое значение неизвестно. Поэтому нужен небольшой трюк: программа сначала считывает текущее значение, а затем записывает новое, тоже с помощью CAS, потому что запись могла успеть поменяться даже за этот шаг. Эта попытка чтения+записи повторяется в цикле, пока старое значение не совпадет и переменная не будет успешно записана.
Этот трюк называется double-checked или optimistic locking, и может быть использован и в пользовательском коде с любым способом синхронизации. Оптимистичность заключается в том, что мы надеемся что состояния гонки нет, прибегая к синхронизации только если гонка всё же случилась. Реализация оптимистичной блокировки может быть дана как отдельная задача.
Начнем с того, что такое атомики и зачем нужны. Atomic* – семейство классов из java.util.concurrent. Они предоставляют набор атомарных операций для соответствующих типов. Например с помощью методов getAndIncrement/incrementAndGet класса AtomicInteger можно делать неатомарный в обычных условиях инкремент (i++).
Условно можно разделить подходы реализации большинства atomic-методов на две группы: compare-and-set и set-and-get.
Методы категории compare-and-set принимают старое значение и новое. Если переданное старое значение совпало с текущим, устанавливается новое. Обычно делегируют вызов в методы класса Unsafe, которые заменяются нативными реализациями виртуальной машины. Виртуальная машина в большинстве случаев использует атомарную операцию процессора compare-and-swap (CAS). Поэтому атомики обычно более эффективны чем стандартная дорогостоящая блокировка.
В случае set-and-get старое значение неизвестно. Поэтому нужен небольшой трюк: программа сначала считывает текущее значение, а затем записывает новое, тоже с помощью CAS, потому что запись могла успеть поменяться даже за этот шаг. Эта попытка чтения+записи повторяется в цикле, пока старое значение не совпадет и переменная не будет успешно записана.
Этот трюк называется double-checked или optimistic locking, и может быть использован и в пользовательском коде с любым способом синхронизации. Оптимистичность заключается в том, что мы надеемся что состояния гонки нет, прибегая к синхронизации только если гонка всё же случилась. Реализация оптимистичной блокировки может быть дана как отдельная задача.
👍15🔥2