Java: fill the gaps
12.9K subscribers
7 photos
215 links
Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк

🔥Тот самый курс по многопочке🔥
https://fillthegaps.ru/mt

Комплименты, вопросы, предложения: @utki_letyat
Download Telegram
Channel created
Fairness. Честная многопоточность.

Одна из проблем многопоточного программирования называется starvation. Её суть в том, что поток не может получить доступ к общим ресурсам и продолжать работу. Так получается, если:
- у потока низкий приоритет,
- другие потоки захватывают доступ к критической секции быстрее,
- поток вызвал wait() у объекта, но notify() достаётся другим потокам.

Ситуация неприятная: ресурсы потока заняты, а задача не выполняется. Чтобы избежать проблем выше можно использовать средства синхронизации с флажком fairness = true. Например,
Lock lock = new ReentrantLock(true);

Что при этом происходит? И почему этот параметр по умолчанию false?
При fairness=true преимущество получает самый долго ожидающий поток. При этом вероятность starvation ощутимо снижается. Конкретная очередность не гарантируется, так как параметр не влияет на планировщик потоков в ОС. Пропускная способность при этом ухудшается в разы

Интересный факт:
tryLock() не обращает внимания на параметр fairness и постарается захватить блокировку, даже если в очереди стоят другие потоки.
tryLock(0, TimeUnit.SECONDS) учитывает fairness и при наличии других ожидающих потоков встанет в общую очередь.

Что же делать? Использовать флажок fairness или нет?
Если описанные выше проблемы возможны и критичны, надёжнее использовать tryLock с увеличивающимся временем ожидания и не полагаться на fairness.

#core
👍132🔥2
Как стать лучшим разработчиком

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

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

Лучший разработчик делает то же, что и хороший. Но не просто поглощает факты, а разбирается, почему всё работает именно так. Какие границы применимости у новых знаний. Чем один подход лучше другого.

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

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

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

В разработке ПО полно инертности. Однажды выбранные способы решения выбираются снова и снова. Thinking out of the box — самый редкий и ценный навык и над ним тоже нужно работать.

#soft_skills
👍212👎1🔥1
Бесполезная калибровка Thread.sleep
или как JDK создаёт иллюзию выбора.

Все знают метод sleep(long millis) у класса Thread. Он останавливает выполнение потока на заданное количество миллисекунд.
Также в классе есть похожий метод sleep(long millis, int nanos). Здравый смысл подсказывает, что это тот же sleep, только время приостановки задаётся точнее.

Документация к методу подтверждает нашу догадку:
...sleep for the specified number of milliseconds plus the specified number of nanoseconds.

Что тут ещё обсуждать? Расходимся!

Но всё же посмотрим в код. После проверок на валидность, видим следующие строки:
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);

То есть прибавить 1 миллисекунду, если наносекунд больше 500к.
Или выставить паузу в 1 миллисекунду, если микросекунд 0, а наносекунд не 0.

У JVM доступен один нативный метод, который работает только с миллисекундами. Поэтому результат не очень удивляет. Но зачем тогда нужен второй метод?

#core
👍81🔥1
Виды многозадачности
Сегодня выйдем за пределы JVM и посмотрим на многопоточность на уровне ОС.

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

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

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

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

#теория
👍8🔥21
Эффективное код ревью
и как сделать его лучше.

Практика код ревью используется на многих проектах, потому что это:
1. Обмен знаниями о проекте и технологиях внутри команды.
2. Повышение качество кода.
3. Способ найти оптимальное решение задачи.

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

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

На верхнем уровне это все понимают, но чтобы на практике увеличить прозрачность и эффективность этого процесса, нужно обсудить и чётко обозначить:
1. Время, в течение которого ревьюеры обязаны посмотреть код.
2. Код-стайл команды — обычно в виде файла для настройки форматирования IDE
3. Приоритеты при решении задачи:
- производительность (высоконагруженные системы),
- чистота кода (open-source проекты),
- лёгкость понимания (проекты с большим количеством разработчиков),
- простота модификации (стартапы)
и тд.
4. Действия при разногласиях - чаще всего это предоставить решение третьей стороне конфликта

2 часа обсуждать имя переменной - это трата времени. Не надо так.

#soft_skills
👍81🔥1
Создание потока в 1995 и в 2020 году
Что происходит, когда программист пишет
new Thread(...)?

В джаве используется модель native threads. Это значит, что потоки создаются в операционной системе(ОС), а в JVM хранится часть контекста.
Планирование очередности и переключения между потоками тоже делает ОС. Процессорные ресурсы используются очень эффективно. В этом главное преимущество модели native threads.

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

В Java 1.1 использовалась другая модель многопоточности, которая называется green threads. В этом случае для JVM создаётся один или несколько системных потоков, а программные потоки с ними соотносятся. Переключение между потоками и работа с контекстом также выполняется JVM.
эмуляции многопоточной среды там, где это не поддерживается ОС.
быстрое переключение между потоками.
нерациональное использование ресурсов в многопроцессорной среде. С точки зрения ОС задачи выполняются псевдопараллелльно, что ухудшает производительность.

Модель green threads устарела и считается неэффективной. Методы ручного управления потоками помечены @Deprecated начиная с Java 1.2.
Но идея переиспользования созданных ОС потоков сейчас в тренде. Java-библиотеки и некоторые версии JVM основаны на идее легковесных потоков. Fibers, coroutines, project Loom, Quasar, Kilim, Kotlin continuations – ключевые слова для дальнейшего углубления в тему.

#теория
👍61🔥1
Паттерн Barrier, ч.1

Если для выполнения задачи нужно дождаться завершения других параллельных задач, то используется паттерн Barrier или барьерная синхронизация.

В нём есть 2 типа участников:
1️⃣ Исполнители — выполняют параллельные задачи и сигнализируют об окончании.
2️⃣ Наблюдатели — ждут завершения указанного количества задач.

В пакете java.util.concurrent этот паттерн реализуют 3 класса:
CountDownLatch
CyclicBarrier
Phaser

В основе их реализации лежит счётчик. Каждый поток, который завершил задачу, уменьшает его значение. Барьер переходит в состояние "преодолён", когда счётчик достигает 0.

Посмотрим, как в них распределены роли:
✔️ CountDownLatch — чёткое разделение на исполнителей и наблюдателей. Потоки исполнителей уменьшают счётчик, затем могут продолжить работу или завершиться. Наблюдатели ждут преодоления барьера, затем выполняют свою задачу.
✔️ CyclicBarrier — роли исполнителей и наблюдателей совмещены. Поток завершает задачу, уменьшает счётчик и блокируется в ожидании остальных. Можно добавить действие, который выполнит последний поток перед тем, как барьер будет считаться преодолённым.
✔️ Phaser комбинирует функционал CountDownLatch и CyclicBarrier и допускает разные варианты использования. Исполнитель может ждать преодоления барьера, а может просто уменьшить счётчик и пойти дальше.

Это основная концептуальная разница между инструментами, которая определяет когда какой использовать. Больше технических аспектов рассмотрим в части 2.

#core
3👍3🔥1
Паттерн Barrier, часть 2
В предыдущей части мы рассмотрели разные реализации паттерна Barrier в java.util.concurrent.

Посмотрим на отличия в использовании. Они касаются того
▪️когда ставится начальное значение счётчика,
▪️что происходит после преодоления барьера.

1️⃣ CountDownLatch
✔️ Счётчик задаётся при создании объекта.
✔️ Поток, который встал на await(), блокируется без возможности прерывания.
✔️ Когда значение счётчика достигает 0, наблюдатель продолжает работу, а сам объект CountDownLatch больше использовать нельзя, он одноразовый.

2️⃣ CyclicBarrier
✔️ Начальное значение счётчика тоже задаётся в конструкторе.
✔️ Поток, который дошёл до барьера, блокируется.
✔️ При преодолении барьера счётчик возвращается в исходное значение и готов снова собирать потоки. Количество циклов бесконечно.

3️⃣ Phaser. Каждый цикл называется фазой.
✔️ Начальное значение счётчика может меняться в каждой фазе.
✔️ Количество фаз по умолчанию бесконечно, но можно выставить ограничение с помощью функции onAdvance.
✔️ Ожидание наблюдателей может быть блокирующим или прерываемым.

Phaser включает в себя весь функционал CountDownLatch и CyclicBarrier. Он гибкий и помогает реализовывать сложные сценарии.

При выборе класса для реализации барьера, помните простую мудрость:
✴️ Если задача решается просто, нужно решать её просто.

#core
2👍1
Как получать достойную зарплату

Вы на собеседовании. Отвечаете на вопросы, рассказываете о своём опыте. Проходит час, а может быть и два. Разговор подходит к концу и Вам задают вопрос:
- На какую зарплату рассчитываете?💰

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

1️⃣ До собеседования:
▪️прибавить к текущей зарплате 15 тысяч. Это сумма, при которой смена работы имеет смысл.
▪️Посмотреть требования и зарплаты в вакансиях, где зарплаты указаны. Уровень оплаты труда и требования меняются каждые полгода, скорректируйте желаемую цифру с опорой на эти данные.

2️⃣ На собеседовании. Здесь есть два варианта:
🅰️ В вакансии указан диапазон зарплат.
Ваша сумма в неё попадает — всё супер.
▪️ Если на собеседовании Вы уверенно ответили на вопросы и впечатлили интервьюера опытом, то назовите цифру чуть больше планируемой. Не стесняйтесь, компании готовы платить за хорошего специалиста.
▪️ Если собеседование прошло так себе, называйте запланированную ранее сумму. Вы ничего не теряете, а может оказаться, что недовольны собеседованием только Вы.

🅱️ В вакансии зарплата не указана.
▪️ Оцените сложность вопросов и длительность интервью. Если оно длится больше часа, и вопросы сложнее обычного, то Вас рассматривают как перспективного кандидата. В таком случае называйте сумму чуть повыше.
▪️ Если интервью было обыкновенное, называйте запланированную цифру.

❗️Важно❗️
1️⃣ Низкая желаемая зарплата не даёт никакого преимущества. В первую очередь оцениваются профессиональные навыки.
Даже если Вы на собеседовании в компанию мечты, не демпингуйте. Лучше скажите эйчару и интервьюеру как сильно Вы хотите здесь работать, это повлияет на результат гораздо сильнее.
2️⃣ Зарплата до вычета налогов называется gross, после вычета — net. Прибавляйте «на руки» или net, когда называете цифру, это поможет избежать недоразумений.

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

#собеседование
👍1🔥1
Java 14 features

Меньше двух недель осталось до выхода новой версии java. 17 марта анонсирован релиз JDK 14. В нём будет 16 фич, давайте посмотрим на некоторые из них.

1️⃣ Текстовые блоки — многострочные строки, ограниченные тремя двойными кавычками.
String html = """
select *
from users
""";
То, ради чего многие перешли на котлин, теперь есть и в java.
Удобно для чтения и написания частей HTML, XML, SQL, JSON.

2️⃣ Изменения в switch.
появился способ не писать break. Если использовать вместо двоеточия стрелочку
то выполнится только код этого кейса.
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);

Напомню, что если в обычной форме не написать в конце блока break, то поиск соответствий после выхода из блока продолжится. В примере напечатаются обе строки:
case 1: System.out.println("1");
default: System.out.println("0");

switch теперь возвращает значение. Если строк много, то используется слово yield.
int j = switch (day) {
case MONDAY -> 0;
case TUESDAY -> 1;
default -> {
int res = f(k);
yield res;
}
};

3️⃣ Сокращение размера кода при сужении типа. Каждому, кто переопределял метод equals, знаком этот паттерн:
if(o instanceof String) {
String s = (String) o;
// use s
}

Теперь проверка и приведение типа объединены:
if(o instanceof String str) {
// can use str here
}

Если в if несколько условий, то область видимости переменной зависит от типа их связи. В условиях, соединённых через И, переменную можно использовать:
if(o instanceof String s && s.length() > 5)

В условиях, соединённых через ИЛИ, переменная не будет видна:
if(o instanceof String s || s.length() > 5)

4️⃣ Больше информации в NullPointerException.
Теперь при возникновении исключения будет доступна не только строка, где это произошло, но и описание ситуации.
Exception in thread "main" java.lang.NullPointerException:
Cannot read field "j" because "b" is null
at Pr.main(Pr.java:5)

По умолчанию эта фича не работает, для её включения нужно установить флаг:
-XX:+ShowCodeDetailsInExceptionMessages

#core
👍72🔥2
10 must-have навыков java разработчика в 2020.

1️⃣ Понимать принципы CI/CD.
В 2020 разработчик представляет себе весь процесс релиза - от коммита до выхода в продакшн и умеет пользоваться инструментами devOps— Jenkins, Docker, Kubernetes, Chef, Ansible.

2️⃣ Применять фичи Java 8-13.
Новая версия Java выходит каждые полгода. Тренды и инструменты разработки меняются быстро, но язык программирования — основа каждой системы. Изучение его возможностей должно стать приоритетом.

3️⃣ Знать Spring framework и его проекты.
Большинство энтерпрайз решений используют Spring как основной фреймворк. К нему часто прибавляется Spring MVC, Spring Boot, Spring Data и Spring Cloud. Знать возможности спринга и уметь ими пользоваться — необходимый навык в 2020.

4️⃣ Писать качественные тесты.
Тестирование — основной инструмент повышения качества кода. Чем больше и сложнее продукт, тем выше его роль. Junit и Mockito — основные библиотеки для юнит-тестов, Testcontainers и Spring Test — для интеграционного.

5️⃣ Пользоваться библиотеками.
Вместо самописного велосипеда лучше использовать уже оптимизированные и протестированные методы из библиотек. Jackson and Gson для JSON, JAXB для работы с XML, SLF4j — для логгирования, Google Guava и Apache Commons помогут сконцентрироваться на бизнес-задачах.

6️⃣ Понимать работу JVM.
Из каких частей состоит JVM и как они взаимодействуют. JIT, JVM опции, виды и принципы сборки мусора, умение профилировать приложение и анализировать результаты — необходимые шаги к высокопроизводительным приложениям.

7️⃣ Применять паттерны проектирования
Это поможет писать тестируемый и расширяемый код. Паттерны GoF и параллельного программирования — базовый арсенал разработчика при решении задач.

8️⃣ Изучать другие языки программирования.
Изучение других подходов к решению задач расширяет кругозор и помогает в работе. Для Java разработчиков основной источник вдохновения - Kotlin, но изучить Scala, JavaScript, Go или Python — тоже хорошая идея.

9️⃣ Знать принципы разработки микросервисной архитектуры.
Микросервисы — глобальный тренд, всё больше проектов предпочитают этот подход монолиту. Spring Cloud и Spring Boot – основной инструментарий для построения микросервисов.

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

#прочее
7👍4🔥1
5 неочевидных советов, чтобы пройти (почти) любое собеседование

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

5 важных рекомендаций для успешного интервью:

1️⃣ Улыбайтесь.
Решение о найме часто принимается в первые 2 минуты общения, а следующий час интервьюер ищет подтверждение сделанному выбору. Улыбка - самый простой способ повысить доверие и очаровать собеседника.

2️⃣ Подготовьте рассказ о предыдущем проекте.
Опыт - главный актив разработчика и правильно его преподнести — 70% успеха на собеседовании. Как это сделать — тема отдельного поста. Кратко - ценный сотрудник - это тот, кто видит общую картину проекта и понимает свой вклад в неё.

3️⃣ Говорите чётко и структурированно, не перебивайте.
Умение формулировать и доносить свои мысли - основа взаимодействия с будущими коллегами. Какими бы глубокими ни были Ваши знания java, для работы в команде нужны навыки эффективного общения.

4️⃣ Расскажите о своих приоритетах.
Работа на результат, чистый код или производительность - не просто красивые слова, а то, на чём основываются ежедневные решения. Постарайтесь донести свои ценности до интервьюера.
Подсказка: упоминайте приоритеты при ответах на технические вопросы. Сложный концептуальный вопрос — опишите несколько вариантов и упомяните, что решение лучше обсудить с опытными коллегами. Задача с запутанным синтаксисом - упомяните, что Вы за читаемость и никогда не будете так писать.

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

Удачных собеседований!

#собеседование
👍6🔥21
Блокировки в HotSpot JVM

Java Virtual Machine(JVM) - это посредник между скомпилированной кодом и операционной системой (ОС). Благодаря такой схеме можно легко запускать java приложения на разных платформах. Реализаций JVM много, но самой распространённой является бесплатная HotSpot от OpenJDK.

JVM не просто переводит java команды в команды ОС. Виртуальная машина реализуется так, чтобы выполнять код эффективнее и быстрее.
Рассмотрим, например, как HotSpot оптимизирует действие «взять блокировку».
У JVM есть 3 способа реализации:
▪️Fat или inflated : на основе мониторов объектов (мьютексов). Подходит для случаев, когда есть много претендентов на захват блокировки.
▪️Thin или deflated : с использованием CAS команд. Это быстрее, чем использовать мьютексы. Но из-за необходимости эксклюзивного доступа в условиях большой конкуренции между потоками этот подход неэффективен.
▪️Biased: оптимизированный тип блокировки для случаев, когда с объектом в основном работает один поток. При первом взаимодействии объект ассоциируется с потоком и дальнейшие действия происходят без лишних синхронизаций. Если другой поток захочет захватить блокировку, то начнётся глобальная перестройка или bulk revocation. Это очень неэффективно и для активно конкурирующих сценариев, например, producer-consumer, такой тип блокировки не подойдёт.

Biased блокировка отключена на старте приложения, потому что в этот момент происходит много междупоточных взаимодействий. Но спустя некоторое время она включается и является блокировкой по умолчанию.
Её можно отключить с помощью опции:
-XX:-UseBiasedLocking
Время включения после старта регулируется флажком
-XX:BiasedLockingStartupDelay=500
По умолчанию это значение равно четырём секундам.

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

#теория
👍2
Утренний java puzzle♨️

Проверь себя и узнай правильный ответ в статье через час.