Что выведет следующий код?
Anonymous Quiz
19%
Произойдет RuntimeException на строке 4
3%
Произойдет RuntimeException на строке 5
14%
Произойдет RuntimeException на строке 6
35%
nullnullnullnullnull
29%
Код не скомпилируется
👍16🍾3😢2☃1
Из чего состоит пакет java.nio?
Этому вопросу посвящена отдельная страница документации. Если вы никогда раньше не сталкивались с Java NIO – это хорошее место для начала знакомства. Отвечая на этот вопрос, нужно перечислить и объяснить основные понятия NIO:
Буфферы. Временные хранилища фиксированного размера для транспортируемых данных. Именно буферизация – основное отличие неблокирующего чтения от java.io.
Каналы. Реализации интерфейса Channel – сущности, представляющие соединения между разными участниками ввода-вывода (файлы, сокеты, консоль).
Селекторы. Наследники класса Selector. «Мультиплексоры» каналов – комбинируют несколько каналов в один. Регистрация канала в селекторе возвращает SelectionKey, который содержит ссылку на сам канал, и ряд его атрибутов. Селектор позволяет выбрать из набора зарегистрированных каналов подмножество готовых к работе, при необходимости блокируя выполнение на время ожидания. Каналы и селекторы располагаются в пакете java.nio.channels. Полный пример использования селекторов можно найти в статье на baeldung.
Кодировки. Charset – то, как бинарные данные будут конвертироваться в родные для Java символы UTF-16 и обратно. Классы для работы с кодировками хранятся в пакете java.nio.charset.
Этому вопросу посвящена отдельная страница документации. Если вы никогда раньше не сталкивались с Java NIO – это хорошее место для начала знакомства. Отвечая на этот вопрос, нужно перечислить и объяснить основные понятия NIO:
Буфферы. Временные хранилища фиксированного размера для транспортируемых данных. Именно буферизация – основное отличие неблокирующего чтения от java.io.
Каналы. Реализации интерфейса Channel – сущности, представляющие соединения между разными участниками ввода-вывода (файлы, сокеты, консоль).
Селекторы. Наследники класса Selector. «Мультиплексоры» каналов – комбинируют несколько каналов в один. Регистрация канала в селекторе возвращает SelectionKey, который содержит ссылку на сам канал, и ряд его атрибутов. Селектор позволяет выбрать из набора зарегистрированных каналов подмножество готовых к работе, при необходимости блокируя выполнение на время ожидания. Каналы и селекторы располагаются в пакете java.nio.channels. Полный пример использования селекторов можно найти в статье на baeldung.
Кодировки. Charset – то, как бинарные данные будут конвертироваться в родные для Java символы UTF-16 и обратно. Классы для работы с кодировками хранятся в пакете java.nio.charset.
👍13
👍15🤯14🌭1
Что такое ForkJoinPool?
ForkJoinPool – специальный вид ExecutorService (пулла потоков), который появился в Java с версии 7. Предназначен для выполнения рекурсивных задач.
Задача для сервиса представляется экземпляром класса ForkJoinTask. В основном используются подклассы RecursiveTask и RecursiveAction, для задач с результатом и без соответственно. Аналогично интерфейсам Callable и Runnable обычного ExecutorService.
Тело рекурсивной операции задается в реализации метода compute() задачи ForkJoinTask. Здесь же создаются новые подзадачи, и запускаются параллельно методом fork(). Чтобы дождаться завершения выполнения задачи, на каждой форкнутой подзадаче вызывается блокирующий метод join(), результат выполнения при необходимости агрегируется.
С точки зрения использования метод ForkJoinTask.join() похож на аналогичный метод класса Thread. Но в случае fork-join поток может на самом деле не заснуть, а переключиться на выполнение другой задачи. Такая стратегия называется work stealing, и позволяет эффективнее использовать ограниченное количество потоков. Это похоже на переиспользование потоков корутинах Kotlin (green threads).
Примеры практического использования ForkJoinPool.
ForkJoinPool – специальный вид ExecutorService (пулла потоков), который появился в Java с версии 7. Предназначен для выполнения рекурсивных задач.
Задача для сервиса представляется экземпляром класса ForkJoinTask. В основном используются подклассы RecursiveTask и RecursiveAction, для задач с результатом и без соответственно. Аналогично интерфейсам Callable и Runnable обычного ExecutorService.
Тело рекурсивной операции задается в реализации метода compute() задачи ForkJoinTask. Здесь же создаются новые подзадачи, и запускаются параллельно методом fork(). Чтобы дождаться завершения выполнения задачи, на каждой форкнутой подзадаче вызывается блокирующий метод join(), результат выполнения при необходимости агрегируется.
С точки зрения использования метод ForkJoinTask.join() похож на аналогичный метод класса Thread. Но в случае fork-join поток может на самом деле не заснуть, а переключиться на выполнение другой задачи. Такая стратегия называется work stealing, и позволяет эффективнее использовать ограниченное количество потоков. Это похоже на переиспользование потоков корутинах Kotlin (green threads).
Примеры практического использования ForkJoinPool.
👍20🔥1
Что выведет следующий код?
Anonymous Quiz
62%
It’s me!
5%
Выдаст IOException во время выполнения
9%
Выдаст Exception во время выполнения
24%
Код не скомпилируется
👍13🤔9🍾1
Чем ForkJoinPool отличается от ExecutorService?
ForkJoinPool сам по себе является наследником ExecutorService. Вопрос подразумевает его отличия от обычного пула потоков – ThreadPoolExecutor.
Преимущества, которые дает work stealing по сравнению с обычным пулом:
• Сокращение расходов на переключение контекста;
• Защита от проблемы голодания потоков (thread starvation);
• Защита от дедлока для рекурсивных задач.
Как положено любому представителю ExecutorService, ForkJoinPool тоже умеет выполнять Runnable и Callable, но помимо этого работает и со специальными задачами ForkJoinTask, о которых также говорилось ранее.
Интерфейс настройки и мониторинга остается тем же, что и в классических тред-пулах.
Каждый обычный пул использует собственный набор потоков. ForkJoinPool по умолчанию использует общий пул-синглтон commonPool. Альтернативный отдельный пул всё еще можно задать в конструкторе.
ForkJoinPool сам регулирует количество запущенных потоков, достигая максимальной эффективности при заданном уровне параллелизма.
ForkJoinPool сам по себе является наследником ExecutorService. Вопрос подразумевает его отличия от обычного пула потоков – ThreadPoolExecutor.
Преимущества, которые дает work stealing по сравнению с обычным пулом:
• Сокращение расходов на переключение контекста;
• Защита от проблемы голодания потоков (thread starvation);
• Защита от дедлока для рекурсивных задач.
Как положено любому представителю ExecutorService, ForkJoinPool тоже умеет выполнять Runnable и Callable, но помимо этого работает и со специальными задачами ForkJoinTask, о которых также говорилось ранее.
Интерфейс настройки и мониторинга остается тем же, что и в классических тред-пулах.
Каждый обычный пул использует собственный набор потоков. ForkJoinPool по умолчанию использует общий пул-синглтон commonPool. Альтернативный отдельный пул всё еще можно задать в конструкторе.
ForkJoinPool сам регулирует количество запущенных потоков, достигая максимальной эффективности при заданном уровне параллелизма.
👍19🌭1🍌1🍾1
Что выведет следующий код?
Anonymous Quiz
28%
012012012
11%
000111222
2%
010120212
59%
Все варианты правильные
👍15☃11😁7🥴4🌭3
Как работают параллельные стримы?
Основная цель, ради которой в Java 8 был добавлен Stream API – удобство многопоточной обработки.
Обычный стрим будет выполняться параллельно после вызова промежуточной операции parallel(). Некоторые стримы создаются уже многопоточными, например результат вызова Collection#parallelStream(). Для распараллеливания используется единый общий ForkJoinPool.
Внутри реализации потока его сплиттератор оборачивается в AbstractTask, который и отправляется на выполнение в пул. AbstractTask при выполнении считывает estimateSize сплиттератора и текущую степень параллелизма пула. На основе этих данных он принимает решение, распараллелить ли сплиттератор на два методом trySplit().
У удобства такого решения есть обратная сторона. Так как пул единый, нагрузка распределяется на всех пользователей параллельных стримов в программе. Если в одном потоке выполняются долгие блокирующие операции, это может ударить по производительности в совершенно не связанном с ним другом потоке.
Если всё же требуется использовать отдельный пул потоков, сам стрим выполняется как задача этого отдельного пула. Подробнее в статье.
Основная цель, ради которой в Java 8 был добавлен Stream API – удобство многопоточной обработки.
Обычный стрим будет выполняться параллельно после вызова промежуточной операции parallel(). Некоторые стримы создаются уже многопоточными, например результат вызова Collection#parallelStream(). Для распараллеливания используется единый общий ForkJoinPool.
Внутри реализации потока его сплиттератор оборачивается в AbstractTask, который и отправляется на выполнение в пул. AbstractTask при выполнении считывает estimateSize сплиттератора и текущую степень параллелизма пула. На основе этих данных он принимает решение, распараллелить ли сплиттератор на два методом trySplit().
У удобства такого решения есть обратная сторона. Так как пул единый, нагрузка распределяется на всех пользователей параллельных стримов в программе. Если в одном потоке выполняются долгие блокирующие операции, это может ударить по производительности в совершенно не связанном с ним другом потоке.
Если всё же требуется использовать отдельный пул потоков, сам стрим выполняется как задача этого отдельного пула. Подробнее в статье.
👍17🔥6
Что выведет следующий код?
Anonymous Quiz
26%
%X%x%x%x%x%x%x10101010101010
24%
Aaaaaaa
43%
10101010101010
8%
%X%x%x%x%x%x%x
👍31☃5🌚2🌭2🥴1
Чем CompletableFuture отличается от Future?
Future – интерфейс, который представляет пока еще недовычисленный результат. Когда породившая его асинхронная операция заканчивается, он заполняется значением. Метод get блокирует выполнение до получения результата, isDone проверяет его наличие. К примеру результат выполнения задач в ExecutorService, ForkJoinTask, реализует интерфейс Future.
CompletableFuture появился в Java 8. Это класс-реализация старого интерфейса Future, а значит всё сказанное выше справедливо и для него. Вдобавок к этому, CompletableFuture реализует работу с отложенными результатами посредством коллбэков. Метод thenApply регистрирует код обработки значения, который будет автоматически вызван позже, когда это значение появится.
В Java 9 прогресс пошел дальше, и появилась библиотека Flow API. Это встроенная реализация реактивных стримов. Реактивный стрим, сильно упрощая, – это более общий случай, последовательность отложенных значений. Другая их реализация – популярная, но не входящая в стандарт библиотека Reactive Extensions (RxJava).
Future – интерфейс, который представляет пока еще недовычисленный результат. Когда породившая его асинхронная операция заканчивается, он заполняется значением. Метод get блокирует выполнение до получения результата, isDone проверяет его наличие. К примеру результат выполнения задач в ExecutorService, ForkJoinTask, реализует интерфейс Future.
CompletableFuture появился в Java 8. Это класс-реализация старого интерфейса Future, а значит всё сказанное выше справедливо и для него. Вдобавок к этому, CompletableFuture реализует работу с отложенными результатами посредством коллбэков. Метод thenApply регистрирует код обработки значения, который будет автоматически вызван позже, когда это значение появится.
В Java 9 прогресс пошел дальше, и появилась библиотека Flow API. Это встроенная реализация реактивных стримов. Реактивный стрим, сильно упрощая, – это более общий случай, последовательность отложенных значений. Другая их реализация – популярная, но не входящая в стандарт библиотека Reactive Extensions (RxJava).
👍15🔥2❤1
Что выведет следующий код?
Anonymous Quiz
35%
Short int
11%
Number Number
21%
Short Number
33%
int Number
👍24😁5🍾3🏆1
Что лучше, ArrayList или LinkedList?
Самый избитый вопрос. Проверяет знание особенностей реализации (кишки ArrayList, кишки LinkedList) и эффективности операций в этих разных реализациях. В вопрос иногда добавляют Vector – пересинхронизированный и устаревший вариант ArrayList, который лучше заменить Collections.synchronizedList().
ArrayList хранит данные в массиве, LinkedList в двусвязном списке. Из этого вытекает разница в эффективности разных операций: ArrayList лучше справляется с изменениями в середине и ростом в пределах capacity, LinkedList – на краях. В целом обычно ArrayList лучше.
Стоит добавить, что для работы на краях лучше использовать реализации специально для этого спроектированного интерфейса Deque: например реализующую кольцевой буфер ArrayDeque.
Самый избитый вопрос. Проверяет знание особенностей реализации (кишки ArrayList, кишки LinkedList) и эффективности операций в этих разных реализациях. В вопрос иногда добавляют Vector – пересинхронизированный и устаревший вариант ArrayList, который лучше заменить Collections.synchronizedList().
ArrayList хранит данные в массиве, LinkedList в двусвязном списке. Из этого вытекает разница в эффективности разных операций: ArrayList лучше справляется с изменениями в середине и ростом в пределах capacity, LinkedList – на краях. В целом обычно ArrayList лучше.
Стоит добавить, что для работы на краях лучше использовать реализации специально для этого спроектированного интерфейса Deque: например реализующую кольцевой буфер ArrayDeque.
👍33
Какой шаблон проектирования использован при реализации пула строк?
Anonymous Quiz
41%
Одиночка (Singleton)
25%
Приспособленец (Flyweight)
28%
Фабрика (Factory)
6%
Мост (Bridge)
🔥15👍8🌭1
Как удалить элемент из ArrayList при итерации?
Обычно формулируется в виде задачи на внимательность «что здесь не так», например:
Не исключение, но неожиданный результат получится если пользоваться не итератором, а обычным циклом for – при каждом удалении нумерация элементов будет сдвигаться.
Единственный способ удалить элемент из коллекции при обходе, не получив при этом ConcurrentModificationException или неопределенное поведение – удалить с помощью remove() того же инстанса итератора. Вариант ListIterator поможет, если в теле цикла требуется и работа с индексами.
Некоторые коллекции, такие как CopyOnWriteArrayList и ConcurrentHashMap адаптированные под многопоточную среду и имеют fail-safe итераторы.
Обычно формулируется в виде задачи на внимательность «что здесь не так», например:
for (String item : arrayList)Подвох в том, что итератор ArrayList, который используется в таком варианте цикла for, является fail-fast, то есть не поддерживает итерацию с параллельной модификацией. А параллельная модификация случается даже в одном потоке, что демонстрирует этот пример. Следующий шаг итератора после удаления элемента выбросит ConcurrentModificationException.
if (item.length() > 2)
arrayList.remove(item);
Не исключение, но неожиданный результат получится если пользоваться не итератором, а обычным циклом for – при каждом удалении нумерация элементов будет сдвигаться.
Единственный способ удалить элемент из коллекции при обходе, не получив при этом ConcurrentModificationException или неопределенное поведение – удалить с помощью remove() того же инстанса итератора. Вариант ListIterator поможет, если в теле цикла требуется и работа с индексами.
Некоторые коллекции, такие как CopyOnWriteArrayList и ConcurrentHashMap адаптированные под многопоточную среду и имеют fail-safe итераторы.
👍25🌭2🍌1
Бекенд разработчик в HR Tech
- Москва,гибрид/удаленка
- Middle, senior
Наша небольшая команда решает задачи в масштабе всего Яндекса. Мы разработали внутренний Календарь для рабочих встреч, а недавно начали продавать его в пакете сервисов для бизнеса Яндекс 360 (подробно об этом рассказывали на Yandex Scale). А ещё мы разрабатываем карты наших офисов — они похожи на схемы ТЦ на Яндекс Картах. Сейчас прорабатываем прототип с обновлённым дизайном и современной версией движка для отрисовки Яндекс Карт.
Мы ищем опытного разработчика, которого так же, как и нас, воодушевляет преодоление инженерных сложностей и работа над большими системами.
Что нужно делать:
- проектировать архитектуру компонентов системы;
- генерировать идеи вместе с другими членами команды;
- проводить ревью дизайна и кода;
- повышать эффективность, масштабируемость и стабильность системы.
Мы ждем, что вы:
- работали с Java, Kotlin, PostgreSQL, Spring;
- пишете эффективный и понятный код;
- способны объяснять свои решения и работать совместно с коллегами;
- инициативны и внимательны к пожеланиям и проблемам пользователей;
- Москва,гибрид/удаленка
- Middle, senior
Наша небольшая команда решает задачи в масштабе всего Яндекса. Мы разработали внутренний Календарь для рабочих встреч, а недавно начали продавать его в пакете сервисов для бизнеса Яндекс 360 (подробно об этом рассказывали на Yandex Scale). А ещё мы разрабатываем карты наших офисов — они похожи на схемы ТЦ на Яндекс Картах. Сейчас прорабатываем прототип с обновлённым дизайном и современной версией движка для отрисовки Яндекс Карт.
Мы ищем опытного разработчика, которого так же, как и нас, воодушевляет преодоление инженерных сложностей и работа над большими системами.
Что нужно делать:
- проектировать архитектуру компонентов системы;
- генерировать идеи вместе с другими членами команды;
- проводить ревью дизайна и кода;
- повышать эффективность, масштабируемость и стабильность системы.
Мы ждем, что вы:
- работали с Java, Kotlin, PostgreSQL, Spring;
- пишете эффективный и понятный код;
- способны объяснять свои решения и работать совместно с коллегами;
- инициативны и внимательны к пожеланиям и проблемам пользователей;
👍9