Java Guru 🤓
13.2K subscribers
898 photos
15 videos
772 links
Канал с вопросами и задачами с собеседований!

По сотрудничеству и рекламе: @NadikaKir

Канал в перечне РКН: https://vk.cc/cJrSQZ

Мы на бирже: telega.in/channels/javatasks/card?r=lcDuijdm
Download Telegram
Какие бывают тестовые объекты (заглушки)? Чем стаб отличается от мока?

Тестовый объект (Test Double) — объекты, которые необходимы в тестах для подмены внешних зависимостей тестируемого кода.

Типы тестовых объектов:
Dummy — объекты, которые передаются в методы, но не используются. Например: заполнение списка параметров, часто это просто null
Fake — заглушка, являющаяся рабочей имплементацией, но с урезанной функциональностью и неприменима в production-окружении. Например: in-memory БД (fake database)
Stub — заглушка с жестко заданными ответами на вызовы со стороны тестируемого объекта (system under test — SUT) во время теста
Spy — это разновидность Stub, которая записывает информацию о произошедшем с ней, какие вызовы её методов были выполнены и сколько раз, как изменилось состояние и т.п.
Mock — заглушка с ожиданиями определённого набора вызовов, которые будут на ней выполнены в ходе теста

Из данного набора заглушек только Mock используется для верификации поведения, остальные — для верификации состояния тестируемого объекта.
🔥18👍121
Что выведет следующий код?
👍8
Что выведет следующий код?
Anonymous Quiz
33%
1
10%
2
41%
3
15%
4
👍15😱1514🐳5🤨5
Дайте определение полиморфизму

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

1. Универсальный полиморфизм. Он подразделяется на:
Параметрический полиморфизм — описывает вычисления в общем виде, абстрагируясь от конкретных типов, которые будут использованы. Параметрически полиморфные функции также называются обобщенными (Generic).
• Полиморфизм включений (inclusive) — описывает вычисления не только для конкретного типа, но для и всех его возможных подтипов. Отражает
принцип подстановки Барбары Лисков.
2.
Специальный полиморфизм (или ad-hoc) — диспетчеризация (перенаправление) к одной или нескольким функциям для конкретного типа аргумента. Из него выделяют подтипы:
Перегрузка (overloading) позволяет объявлять функции с одним и тем же именем, но с разными типами аргументов и их количеством (арностью).
Неявное приведение типов — преобразование одного типа в другой по определённым правилам, описанным в стандарте языка, и выполняемое компилятором.
👍25😱2🌭2🎉1🍾1
Что выведет следующий код?
👍10😢6
👍18
Какими коллекциями пользоваться в многопоточной среде?

Первый
вариант – превратить в синхронизированную обычную коллекцию, вызвав соответствующий ее типу метод Collections.synchronized*(). Самый общий и самый примитивный способ, создает обертку с синхронизацией всех операций с помощью synchronized.

Если работа с коллекцией состоит в основном из чтения, лучшая в плане производительности альтернатива – CopyOnWriteArrayList, и содержащий его в реализации CopyOnWriteArraySet. Потокобезопасность достигается копированием внутреннего массива при любой модификации, оригинальный массив остается immutable. Program order достигается модификатором volatile на внутреннем массиве.

Третий вариант – использование Concurrent-коллекций:
• Неблокирующие хэш-таблицы ConcurrentSkipListMap, ConcurrentHashMap и ConcurrentSkipListSet (хэш-таблица в основе реализации)
• Неблокирующие очереди ConcurrentLinkedQueue и ConcurrentLinkedDeque
• Большой набор различных блокирующих очередей
👍27
Что выведет следующий код?
👍13
Что выведет следующий код?
Anonymous Quiz
37%
truetruetrue
26%
falsefalsefalse
8%
truefalsetrue
29%
falsefalsetrue
👍14🤨1
Как в лямбде изменить внешнюю локальную переменную?

Это нельзя сделать в лоб. Такой код не скомпилируется, потому что захваченная локальная переменная обязана быть effectively final. Такое требование исходит из следующих причин.

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

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

Поля экземпляра менять можно, потому что захваченной переменной в этом случае выступает effectively final значение this.

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

Хак с оберткой решает проблему времени жизни и даёт коду скомпилироваться, но возвращает проблему сложности поведения. Если среда многопоточная, то вероятно порядок операций с этой переменной придется синхронизировать вручную.
👍21🤯10👏1
Что выведет следующий код?
👍8
Что выведет следующий код?
Anonymous Quiz
25%
254
31%
-2
10%
10
35%
0
🥴25👍73🐳2
Как получить гарантированный дедлок?

Сначала поговорим о том, что это такое. Deadlock – это взаимная блокировка, ситуация, когда два или более потока «наступают друг-другу на хвост» – зависают в вечном ожидании ресурсов, захваченных друг другом.

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

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

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

Нарушение условия даст дедлок «скорее всего когда-нибудь». Чтобы получить его точно и с первого раза, нужно гарантировать, что оба потока окажутся на этапе между захватами одного и другого ресурса в одно время. Это можно сделать множеством способов, в примере ниже использован CyclicBarrier.
👍19
Как отработает приведенный код?
👍9
Как устроены атомики?

Начнем с того, что такое атомики и зачем нужны. 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, и может быть использован и в пользовательском коде с любым способом синхронизации. Оптимистичность заключается в том, что мы надеемся что состояния гонки нет, прибегая к синхронизации только если гонка всё же случилась. Реализация оптимистичной блокировки может быть дана как отдельная задача.
👍171
Что выведет следующий код?
👍11
Что выведет следующий код?
Anonymous Quiz
43%
falsefalse
23%
truefalse
10%
falsetrue
24%
truetrue
👍25
Что такое и как создать daemon thread?

Демон в широком значении – фоновая программа. В Java потоки-демоны имеют схожий смысл: это потоки для фоновых действий по обслуживанию основных потоков. Потоки не-демоны называются пользовательскими (user thread).

Тред создается демоном, если его родитель демон. Свойство Java-треда isDaemon можно переключать в любой момент до старта потока.

По сравнению с пользовательскими потоками демоны имеют меньший приоритет выполнения.

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

Daemon thread может быть полезен для таких действий, как инвалидация кэша, периодическая актуализация значений из внешних источников, освобождение неиспользуемых пользовательских ресурсов.
👍16
Сколько экземпляров String будет создано в результате выполнения приведенного кода?
👍11🍌7