0% нашли этот документ полезным (0 голосов)
121 просмотров23 страницы

Задачник Java

Загружено:

vova13158
Авторское право
© © All Rights Reserved
Мы серьезно относимся к защите прав на контент. Если вы подозреваете, что это ваш контент, заявите об этом здесь.
Доступные форматы
Скачать в формате PDF, TXT или читать онлайн в Scribd
0% нашли этот документ полезным (0 голосов)
121 просмотров23 страницы

Задачник Java

Загружено:

vova13158
Авторское право
© © All Rights Reserved
Мы серьезно относимся к защите прав на контент. Если вы подозреваете, что это ваш контент, заявите об этом здесь.
Доступные форматы
Скачать в формате PDF, TXT или читать онлайн в Scribd

07.10.

2024, 15:50 Задачник

Задачи Шаблоны Как создать задачу?

Поиск по названию, содержанию и разделу Грейд По дате добавлен…

Раздел Найдено задач: 32

Flutter

Тимлид 1. Рассказать про ThreadPool


Java Многопоточность
Компетенции
17 - 19 грейд 3 мин 184 раза Свернуть
Python

1C Рассказать про ThreadPool в Java. Что это такое, зачем они нужны, когда их нужно
применять, какие виды ThreadPool бывают.
Аналитика данных

C++ Ответ

Продуктовый дизайн 17 грейд


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

GO Пулы потоков используют, когда нужно выполнять несколько задач одновременно. Они
помогают управлять количеством потоков и улучшить производительность приложения.
Architecture (System Design)
18 грейд
QA
Пулы потоков — это механизм из Executor framework, который позволяет
.NET переиспользовать фиксированное количество потоков для выполнения большого числа
задач. Это снижает затраты на создание и уничтожение потоков.
Android

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

Дженерики Пулы потоков используют, когда нужно выполнять много задач одновременно, но вы
хотите избежать затрат на создание/уничтожение потоков и возможного истощения
Многопоточность ресурсов. Например, на веб-сервере каждую входящую задачу можно обрабатывать
потоком из пула.
JVM / GC

Инструменты сборки Различные типы пулов потоков:


• FixedThreadPool : подходит для приложений с постоянным количеством задач.
Frontend • CachedThreadPool : для большого числа коротких асинхронных задач.
• ScheduledThreadPool : для задач с задержкой или периодическим выполнением.
Product

DS

Мотивация
2. Механизмы синхронизаций и блокировок
Базы данных(не для Data Java Многопоточность
Engineer)
17 - 20 грейд 5 мин 191 раз Свернуть
Аналитик (бизнес)

Scala Расскажите о механизмах синхронизаций и блокировок в Java. Когда и что нужно


использовать, как они устроены внутри.
Информационная
безопасность
Ответ
Эксплуатация/DevOps
17 грейд
Техническая документация

https://matrix.o3.ru/trials 1/23
07.10.2024, 15:50 Задачник

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

L2 Application Support Знает про synchronized, возможно слышал про wait/notify.

18 грейд
Механизмы синхронизации обеспечивают безопасный доступ нескольких потоков к общим
ресурсам. В Java основные средства синхронизации — это ключевое слово synchronized ,
блокировки (Locks) и атомарные переменные (Atomic Variables).

19 грейд
Механизмы синхронизации в Java включают synchronized блоки, методы, а также более
продвинутые инструменты, такие как Lock из java.util.concurrent и атомарные
операции. Они обеспечивают управление доступом потоков к разделяемым ресурсам,
предотвращая race conditions и deadlocks.

Ключевое слово synchronized :


• Глубокое понимание того, как работает synchronized , включая мониторные блокировки,
рекуррентные блокировки, и внутренние детали работы с памятью (memory model).

Библиотека java.util.concurrent :
• Locks: ReentrantLock , ReadWriteLock , StampedLock – их преимущества над synchronized ,
особенности использования и когда лучше применять каждый из них.
• Condition: Использование Condition с Lock для управления более сложными
взаимодействиями между потоками (например, для реализации очередей с
ожиданием).
• Semaphores: Использование семафоров для управления доступом к ограниченным
ресурсам.
• CountDownLatch: Для ожидания завершения операций несколькими потоками.
• CyclicBarrier: Для синхронизации точек, где несколько потоков должны одновременно
завершить выполнение.

Атомарные операции ( java.util.concurrent.atomic ):


• Использование атомарных переменных ( AtomicInteger , AtomicReference , и т.д.) для
выполнения неблокирующих операций с гарантированной атомарностью.

Volatile:
• Понимание использования volatile для обеспечения видимости изменений
переменных между потоками и предотвращения проблем с кэшированием и
переупорядочением операций.

Non-blocking algorithms:
• Знание неблокирующих алгоритмов и структур данных, таких как ConcurrentHashMap ,
ConcurrentLinkedQueue , и их внутреннее устройство.

ThreadLocal:
• Использование ThreadLocal для создания переменных, специфичных для каждого
потока, что позволяет избежать необходимости синхронизации в некоторых случаях.

Барьеры и соглашения:
• Понимание happens-before отношений в Java Memory Model и как они влияют на
синхронизацию и видимость данных между потоками.
Многопоточная оптимизация:
• Знание продвинутых техник оптимизации многопоточных приложений, таких как
минимизация contention, снижение нагрузки на синхронизацию, и использование lock-
free структур данных.

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

3. В чём разница между int и Integer?


Java Знание языка и ООП

17 - 19 грейд 3 мин 184 раза Свернуть

В чём разница между `int` и `Integer`?

Ответ

https://matrix.o3.ru/trials 2/23
07.10.2024, 15:50 Задачник
17 грейд
int — это примитивный тип данных, который хранит целое число. Integer — это класс-
обертка для int , который позволяет работать с целыми числами как с объектами.

18 грейд
int — это примитивный тип, который хранит значение целого числа напрямую в памяти.
Integer — это объектный тип (класс-обертка), который предоставляет дополнительные
методы для работы с целыми числами и может использоваться в коллекциях, требующих
объектов. Также Integer поддерживает null , тогда как int не может быть null .

Примитивы: хранятся в стеке, не могут хранить null, можно сравнивать через ==


(сравниваем значения, а не ссылки), нет заголовка, копируются при передаче в/из метода.

Объекты: хранятся в куче, могут иметь значение null, передаются по ссылке, надо
реализовывать метод equals для сравнения, есть заголовок.

19 грейд
int — это примитивный тип, который хранит значение целого числа в памяти,
обеспечивая высокую производительность и минимальное потребление памяти. Integer
— это класс-обертка, который позволяет использовать примитивные целые числа в
контексте, где требуются объекты, например, в коллекциях, таких как List или Map .
Integer поддерживает автобоксинг и анбоксинг, что позволяет автоматически
преобразовывать int в Integer и наоборот. Однако это может приводить к накладным
расходам на память и производительность. Также, Integer поддерживает значение null ,
что может быть полезно для обозначения отсутствия значения, но требует
дополнительной обработки, чтобы избежать NullPointerException .

Кэширование значений в диапазоне от -128 до 127 (Integer cache) и как это влияет на
производительность и сравнение объектов Integer .

Какую коллекцию лучше использовать при частом удалении


4.
первого элемента?
Java Коллекции и стримы

17 - 19 грейд 3 мин 190 раз Свернуть

Что лучше использовать при частом удалении первого элемента

Ответ

17 грейд
Для частого удаления первого элемента лучше использовать LinkedList , потому что в нем
удаление первого элемента выполняется быстро.

18 грейд
LinkedList — оптимальный выбор для частого удаления первого элемента, так как в
LinkedList операция удаления первого элемента (метод removeFirst() ) выполняется за
O(1). Это связано с тем, что LinkedList реализован как двусвязный список, где первый
элемент легко удаляется без сдвига остальных элементов.

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

Альтернативой может быть ArrayDeque , если требуется двусторонняя очередь с доступом


как с начала, так и с конца. ArrayDeque также поддерживает удаление первого элемента за
O(1), но с меньшими накладными расходами по сравнению с LinkedList , так как
использует массивы и не требует дополнительных объектов для узлов.

5. Enum из прошлого
Java Задачи

18 - 19 грейд 30 мин 74 раза Свернуть

Реализовать свой перечислимый тип (enum), как если бы до появления современного enum
в Java 1.5.
Нужно реализовать контракт современного Java-enum:
https://matrix.o3.ru/trials 3/23
07.10.2024, 15:50 Задачник
• можно легко получать любое значение энума
• безопасное сравнение значений по ссылке (`==`)
• каждое значение имеет строковое имя, совпадающее с названием значения
• каждое значение имеет целочисленный идентификатор `ordinal`, который содержит
номер значения в порядке его объявления в энуме
• можно получить список всех значений энума
• можно получить значение по его `ordinal`
• можно получить значение по его имени

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

class Currency {
// TODO
}

Ответ

18 грейд
Решение должно выглядеть примерно так:

public class Currency {

private static final Map<String, Currency> valuesByName = new HashMap<>


();
private static final List<Currency> values = new ArrayList<>();

public static final Currency RUB = new Currency("RUB");


public static final Currency USD = new Currency("USD");
public static final Currency EUR = new Currency("EUR");

private final int ordinal;


private final String name;

private Currency(String name) {


ordinal = values.size();
values.add(this);
this.name = name;
valuesByName.put(name, this);
}

public int ordinal() {


return ordinal;
}

public String name() {


return name;
}

public static List<Currency> values() {


return Collections.unmodifiableList(values);
}

public static Optional<Currency> byOrdinal(int ordinal) {


try {
return Optional.of(values.get(ordinal));
} catch (IndexOutOfBoundsException e) {
return Optional.empty();
}
}

public static Optional<Currency> byName(String name) {


return Optional.ofNullable(valuesByName.get(name));
}
}

19 грейд

https://matrix.o3.ru/trials 4/23
07.10.2024, 15:50 Задачник
Еще лучше, если кандидат сможет отказаться от передачи имени в конструкторе:

public class Currency {

private static final Map<String, Currency> valuesByName = new HashMap<>


();
private static final List<Currency> values = new ArrayList<>();

public static final Currency RUB = new Currency();


public static final Currency USD = new Currency();
public static final Currency EUR = new Currency();

static {
for (Field field : Currency.class.getFields()) {
if (Modifier.isStatic(field.getModifiers()) &&
field.getType().equals(Currency.class)) {
try {
Currency currency = (Currency) field.get(null);
currency.setName(field.getName());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}

private final int ordinal;


private String name;

private Currency() {
ordinal = values.size();
values.add(this);
}

private void setName(String name) {


this.name = name;
valuesByName.put(name, this);
}

public int ordinal() {


return ordinal;
}

public String name() {


return name;
}

public static List<Currency> values() {


return Collections.unmodifiableList(values);
}

public static Optional<Currency> byOrdinal(int ordinal) {


try {
return Optional.of(values.get(ordinal));
} catch (IndexOutOfBoundsException e) {
return Optional.empty();
}
}

public static Optional<Currency> byName(String name) {


return Optional.ofNullable(valuesByName.get(name));
}
}

Дополнительные вопросы

На что обратить внимание при решении задачи:


• значения объявляются публичными статическими финальными полями
• значения имеют тип основного класса энума (`Currency`), а не какого-то внутреннего
класса и т.п.
• приватный конструктор

https://matrix.o3.ru/trials 5/23
07.10.2024, 15:50 Задачник
• поле `ordinal` вычисляется автоматически, без явного указания в конструкторе
• метод, возвращающий список всех значений энума защищает этот список от внешних
изменений (а если это массив, то создавать копию массива)
• методы, возвращающие значение по `ordinal`/имени, используют для поиска `Map` или
`List` или поиск по индексу в массиве, а также обрабатывают ситуацию, когда значение
не найдено (кидают исключение или возвращают `Optional`)
• порядок следования статических полей правильный: поля, используемые в
конструкторе, объявлены до самих значений (иначе в конструкторе будет NPE)

Усложнение задачи:
• Реализовать базовый абстрактный класс для любого перечислимого типа

6. Класс и интерфейс
Java Знание языка и ООП

17 - 18 грейд 2 мин 32 раза Свернуть

Чем отличается класс от интерфейса? Какие бывают модификаторы доступа?

Ответ

17 грейд
Class — это шаблон для создания объектов, который может содержать поля и методы.
Interface — это набор абстрактных методов, которые класс должен реализовать.

Модификаторы доступа
• Для class можно использовать модификаторы доступа public , default , private ,
protected .
• Для методов и полей в interface — только public и default .

18 грейд
Class — это структура, содержащая поля и методы, которая может наследоваться от
других классов и реализовывать интерфейсы. Interface определяет набор методов,
которые класс должен реализовать.

• Класс может иметь модификаторы доступа public , protected , private , и default


(package-private).
• Интерфейсы могут быть public или package-private (без модификатора).
• Методы в интерфейсе по умолчанию public , но могут быть default , static , а с Java 9
— private .

7. Jar hell / Classpath hell


Java Инструменты сборки

18 грейд 5 мин 10 раз Свернуть

Что такое Jar hell / classpath hell / dependency hell? Какие последствия, как отловить, как
исправить?

Иногда кандидаты не слышали термин, но сталкивались с проблемой, тогда можно


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

Ответ

Jar hell / classpath hell / dependency hell - ситуация, когда в classpath попадают не те
версии классов, которые ожидались (или вообще отсутствуют). Например, в конфигурации
сборки есть конфликтующие зависимости (или несколько версий одной библиотеки). В
такой ситуации неизвестно из какого jar ClassLoader загрузит классы.

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

Отловить ошибку непросто, нужно анализировать зависимости (хорошо если кандидат


знает как отобразить полное дерево зависимостей).

https://matrix.o3.ru/trials 6/23
07.10.2024, 15:50 Задачник

Единственного правильного способа избежать такой ситуации не существует. Можно


использовать dependency management в инструментах сборки, явный exclude, кастомные
правила resolutionStrategy, shading.

8. Гипотезы о поколениях
Java JVM / GC

18 - 19 грейд 5 мин 6 раз Свернуть

Что такое гипотезы о поколениях? Где и для чего применяются?

Ответ

18 грейд
Гипотеза о поколениях предполагает, что большинство объектов в куче Java "умирают"
молодыми, то есть они быстро становятся недоступными и удаляются сборщиком мусора,
не переходя в область старого поколения. Это знание используется для оптимизации
работы сборщика мусора, разделяя кучу на "молодое" и "старое" поколения, что улучшает
производительность за счет быстрой очистки молодых объектов.

19 грейд
Первая гипотеза (aka "слабая"): большинство объектов умирает молодыми.

Вторая гипотеза (aka "сильная"): объекты из старого поколения редко ссылаются на


объекты из молодого поколения.

Данные гипотезы применяются во многих имплементациях современных GC (как в Java,


так и не только). Данные гипотезы позволяют GC разделять хип на несколько поколений, а
сборки делить на минорные и полные. Минорные сборки происходят чаще, чем полные
сборки и проходятся только по молодым поколениям. Это позволяет увеличить "КПД"
работы GC, проходиться только по объектам, которые умерли с большой вероятностью и
уменьшить время работы и оверхэд GC.

Дополнительные вопросы

Приведите пример воркфлоу нарушающего сильную гипотезу о поколениях?


Ответ: LRU-кэш.

9. Имплементации GC
Java JVM / GC

17 - 20 грейд 5 мин 39 раз Свернуть

Какие имплементации GC в JVM вы знаете? Какие вы использовали? Какие плюсы и


минусы той или иной имплементации знаете?

Ответ

17 грейд
--

18 грейд
Serial GC: Использует один поток для выполнения сборки мусора. Простой и эффективный
для однопоточных приложений или систем с малым количеством процессоров.

Parallel GC (Parallel New GC): Использует несколько потоков для сборки мусора в молодом
поколении, что улучшает производительность на многопроцессорных системах.

G1 GC (Garbage First): Оптимизирован для низких задержек, разбивает кучу на регионы и


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

19 грейд
CMS (Concurrent Mark-Sweep) GC: Параллельный сборщик, минимизирующий паузы,
работает одновременно с приложением. Однако, он может быть менее эффективен с точки
зрения использования CPU и памяти.

https://matrix.o3.ru/trials 7/23
07.10.2024, 15:50 Задачник
20 грейд
Serial GC, Parallel GC, G1 GC, CMS GC: Эксперт понимает их внутренние механизмы, плюсы
и минусы, и знает, как настраивать эти GC для конкретных сценариев.

ZGC (Z Garbage Collector): Низколатентный сборщик мусора, который стремится к


минимальным паузам, даже при работе с большими объемами памяти. Использует технику
"colored pointers" для выполнения большинства операций параллельно с приложением.

Shenandoah GC: Подобен ZGC, но с акцентом на короткие паузы. Подходит для


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

Epsilon GC: "No-op" сборщик мусора, который не выполняет сборку мусора. Используется
для тестирования и анализа поведения приложения без вмешательства сборщика мусора.

10. Зачем нужен GC?


Java JVM / GC

17 - 19 грейд 5 мин 52 раза Свернуть

Зачем нужен GC?

Ответ

17 грейд
GC (Garbage Collector) — это сборщик мусора в Java, который автоматически освобождает
память, занимаемую объектами, которые больше не используются. Это помогает избежать
утечек памяти и упрощает управление памятью, поскольку разработчику не нужно
вручную освобождать память.

18 грейд
GC (Garbage Collector) — это механизм в Java, который управляет памятью, автоматически
обнаруживая и удаляя объекты, которые больше не используются в программе. Он
освобождает разработчика от необходимости вручного управления памятью, снижает
риск утечек памяти и обеспечивает эффективное использование памяти. Сборщик мусора
работает в фоновом режиме, но его работа может влиять на производительность
приложения, создавая паузы в выполнении программы.

19 грейд
GC (Garbage Collector) в Java — это автоматизированный механизм управления памятью,
который отвечает за освобождение памяти, занятой объектами, которые больше не
доступны для использования. Его основная задача — предотвратить утечки памяти и
обеспечить эффективное использование кучи (heap). GC освобождает разработчиков от
ручного управления памятью, что снижает вероятность ошибок, таких как "dangling
pointers" или "double free". Однако работа GC может приводить к паузам в работе
приложения, что критично для систем реального времени. Senior разработчик должен
понимать, как разные алгоритмы сборки мусора (например, G1, CMS, ZGC) влияют на
производительность, и уметь настраивать параметры GC для достижения баланса между
временем пауз и пропускной способностью (throughput) приложения.

Дополнительные вопросы

Q: Какие альтернативные способы управления памятью существуют в разных языках?


A: В языках, в которых нет GC разработчики либо управляют памятью вручную, либо
используют ручной/автоматический подсчёт ссылок.

Q: Какие плюсы и минусы использования GC?


A: Плюсы - проще код, меньше возможностей для ошибки. Минусы - оверхед на работу
самого GC, необходимость пауз stop the world.

Q: Как в общих чертах работает GC?


A: Тут ожидается ответ про вычисление root set, про циклы GC, паузы, поколения, регионы.

Q: Какие особенности появились в G1?


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

https://matrix.o3.ru/trials 8/23
07.10.2024, 15:50 Задачник

11. Как запустить код в отдельном потоке?


Java Многопоточность

17 - 19 грейд 5 мин 24 раза Свернуть

Как запустить код в отдельном потоке?

Ответ

17 грейд
Код можно запустить в отдельном потоке, создав класс, который реализует интерфейс
Runnable , и передав его объект в Thread , а затем вызвать метод start() .

Runnable task = () -> { // Код, который будет выполнен в отдельном потоке


};

Thread thread = new Thread(task);


thread.start();

18 грейд
Использовать ExecutorService из java.util.concurrent для управления потоками,
например, executor.submit() для запуска задачи в отдельном потоке:

ExecutorService executor = Executors.newSingleThreadExecutor();

executor.submit(() -> {
// Код, который будет выполнен в отдельном потоке
});

executor.shutdown();

19 грейд
CompletableFuture: Подходит для асинхронных операций, особенно при работе с
цепочками зависимых задач.

CompletableFuture.runAsync(() -> {
// Код, который будет выполнен асинхронно
});

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


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

12. Volatile
Java Многопоточность

17 - 19 грейд 5 мин 77 раз Свернуть

Что означает ключевое слово volatile в Java?

Ответ

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

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

https://matrix.o3.ru/trials 9/23
07.10.2024, 15:50 Задачник
19 грейд
Кандидат должен быть знаком с JMM, понимать принцип Happens-Before, знать основы
меж-поточного взаимодействия.

Переменная, объявленная как volatile , имеет две ключевые особенности:


1. Гарантия видимости: Все изменения переменной сразу становятся видимыми для всех
потоков, так как операции чтения и записи происходят непосредственно из основной
памяти.
2. Запрет переупорядочивания: Использование volatile предотвращает
переупорядочивание операций с переменной, что может быть критично для
правильного выполнения многопоточных программ.

Однако volatile не гарантирует атомарности операций. Например, инкремент volatile


переменной ( x++ ) все равно не будет потокобезопасным, так как состоит из нескольких
операций (чтение, увеличение, запись). В таких случаях следует использовать
синхронизацию или атомарные переменные из java.util.concurrent.atomic .

• Volatile обеспечивает атомарную запись для long и double переменных вне зависимости
от платформы.
• A write to a volatile field happens-before every subsequent read of that field.

Подробнее: JLS, глава 17

13. Synchronized
Java Многопоточность

17 - 19 грейд 5 мин 27 раз Свернуть

Что такое synchronized?

Ответ

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

18 грейд
synchronized — это механизм синхронизации в Java, который обеспечивает эксклюзивный
доступ к методу или блоку кода для одного потока за раз. Когда поток входит в
synchronized метод или блок, он захватывает монитор объекта, что предотвращает другие
потоки от одновременного выполнения этого же кода. synchronized помогает
предотвратить состояние гонки (race condition), но может привести к блокировкам
(deadlocks), если не использовать его осторожно.

19 грейд
synchronized — это ключевое слово и механизм в Java, обеспечивающий блокировку
доступа к критическому участку кода, чтобы только один поток мог его выполнить в
данный момент времени. Использование synchronized приводит к захвату монитора
объекта, что предотвращает другие потоки от одновременного доступа к этому блоку кода
или методу. Это гарантирует видимость изменений, сделанных внутри synchronized блока,
для всех потоков, а также предотвращает переупорядочивание инструкций в пределах
блока.

Senior разработчик должен понимать:


• Разницу между синхронизацией метода и блока кода.
• Влияние на производительность из-за блокировок (возможность thread contention).
• Возможные проблемы, такие как deadlocks и способы их предотвращения.
• Альтернативы, такие как Lock из java.util.concurrent , которые могут предложить
больше гибкости и контроля над синхронизацией.

14. Atomic-ки
Java Многопоточность

17 - 19 грейд 5 мин 54 раза Свернуть

https://matrix.o3.ru/trials 10/23
07.10.2024, 15:50 Задачник
Что такое Atomic-ки в Java? Приведите примеры использования? Как устроены внутри?

Ответ

17 грейд
Атомарные классы в Java, такие как AtomicInteger , обеспечивают безопасные для потоков
операции без использования synchronized . Они позволяют выполнять операции, такие как
инкремент или сравнение и установка, атомарно, то есть без прерывания другим потоком.

18 грейд
Атомарные классы в Java, такие как AtomicInteger , AtomicLong , и AtomicReference ,
обеспечивают атомарные операции, такие как инкремент, декремент и сравнение-
установка (compare-and-set, CAS), без использования блокировок. Они необходимы для
создания потокобезопасных алгоритмов с высокой производительностью, особенно в тех
случаях, когда использование synchronized может быть излишне дорогим и снижает
производительность.

19 грейд
Atomic* - это набор классов, имеющих полезные комплексные методы с гарантией
атомарности выполнения.

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


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

Атомики часто используются для реализации различных многопоточных (в т.ч. lock-free,


если доступно для платформы) алгоритмов и структур данных (очереди, стеки),
мьютексов, семафоров.

Ожидается, что кандидат знает принцип работы Atomic-ов на x86.

Работа Atomic-ков для большинства платформ основывается на конкретных процессорных


инструкциях и зависит от платформы. К примеру, на x86 это CAS (CMPXCHG), на ARM это
LL/SC и т.д.

15. Пулы потоков


Java Многопоточность

19 грейд 19 мин 11 раз Свернуть

Вопрос: в каком из Executor-ов будет выполнен блок exceptionally?

Function<String, String >throwing = str -> {throw new


RuntimeException("fail");};

CompletableFuture.supplyAsync(() -> "test", firstExecutor)


.thenApplyAsync(throwing, secondExecutor)
.thenAcceptAsync(System.out::println, thirdExecutor)
.exceptionally(th -> {
System.out.println(th.getMessage());
return null;
});

Ответ

Во втором (secondExecutor)

Дополнительные вопросы

Q: а если заменить .thenApplyAsync(throwing,


secondExecutor) на .thenApplyAsync(throwing) ?
A: тогда в ForkJoin-е

16. Runtime Type Identification


Java Дженерики

https://matrix.o3.ru/trials 11/23
07.10.2024, 15:50 Задачник
18 - 19 грейд 3 мин 1 раз Свернуть

Как в runtime узнать, тип генерика в java?

Ответ

18 грейд
Никак, они затираются при компиляции.

19 грейд
Есть трюк с ParameterizedType:

public class GenericTypeExample<T> {


private T data;

public static void main(String[] args) {


GenericTypeExample<String> instance = new GenericTypeExample<>();
Type type =
instance.getClass().getDeclaredField("data").getGenericType();
if (type instanceof ParameterizedType) {
Type actualType = ((ParameterizedType)
type).getActualTypeArguments()[0];
System.out.println("Generic type is: " + actualType);
} else {
System.out.println("Generic type information is not available
due to type erasure.");
}
}
}

17. HashMap / TreeMap


Java Коллекции и стримы

17 - 19 грейд 5 мин 64 раза Свернуть

В чём разница TreeMap и HashMap?


Какая асимптотика на поиск и вставку и того и другого?
Когда нужно применять TreeMap?

Ответ

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

18 грейд
HashMap реализует хэш-таблицу, обеспечивая быстрый доступ к элементам с временем
операции O(1). Порядок элементов не гарантирован. TreeMap реализует красно-черное
дерево и хранит элементы в отсортированном порядке по ключу, обеспечивая время
доступа O(log n). Используйте HashMap для быстрого доступа к данным без требования
порядка. TreeMap подходит, когда важен отсортированный порядок ключей или требуется
выполнять операции диапазона ( subMap , headMap , tailMap ).

19 грейд
HashMap — это структура данных, основанная на хэш-таблице, обеспечивающая
амортизированное время вставки, удаления и поиска O(1), но без гарантий порядка
хранения элементов. TreeMap , с другой стороны, основан на красно-черном дереве и
поддерживает порядок ключей в соответствии с их естественным порядком или с
помощью компаратора. Операции вставки, удаления и поиска в TreeMap выполняются за
O(log n).

Используйте HashMap , когда критически важна скорость доступа и порядок ключей не


имеет значения. Это наиболее часто используемая структура для ассоциативных
массивов. TreeMap следует использовать, когда требуется отсортированный набор
ключей, или нужно часто выполнять операции диапазона, такие как извлечение
поддеревьев. Например, если необходимо сохранить данные в порядке по возрастанию
ключей или работать с диапазонами значений, TreeMap будет более подходящим выбором.
https://matrix.o3.ru/trials 12/23
07.10.2024, 15:50 Задачник

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


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

18. ConcurrentHashMap
Java Коллекции и стримы

18 - 19 грейд 5 мин 6 раз Свернуть

Как устроен ConcurrentHashMap?

Ответ

18 грейд
ConcurrentHashMap — это потокобезопасная версия HashMap , которая позволяет
нескольким потокам одновременно выполнять операции чтения и записи без
необходимости полной блокировки всей структуры данных.

Основная структура ConcurrentHashMap состоит из сегментов (в Java 7) или корзин (в Java


8 и позже), которые позволяют разделять данные и таким образом уменьшать
конкуренцию между потоками.

В Java 8 используется механизм, основанный на CAS (compare-and-swap), для


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

19 грейд
Внутреннее устройство ConcurrentHashMap отличается от HashMap и Hashtable тем, что оно
оптимизировано для многопоточного доступа.

В Java 7 ConcurrentHashMap использует сегментацию, где каждая корзина (bucket)


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

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


механизм CAS (Compare-And-Swap) для выполнения неконкурентных обновлений и
деревообразная структура для разрешения коллизий (как в HashMap ).

ConcurrentHashMap избегает глобальной блокировки, что делает его высокоэффективным в


условиях конкуренции между потоками. Для операций чтения (таких как get ) не
используются блокировки, что позволяет параллельно обслуживать большое количество
запросов. Операции записи (такие как put и remove ) могут использовать минимальную
синхронизацию на уровне корзины, что значительно уменьшает вероятность блокировок
при высокой конкуренции.

Senior разработчик должен понимать, что ConcurrentHashMap обеспечивает слабую


согласованность (weak consistency), что означает, что итераторы могут видеть обновления,
сделанные другими потоками, но не гарантируют, что увидят все изменения. Это
компромисс между производительностью и согласованностью. Также важно понимать, как
правильный размер начальной емкости и степень конкуренции (concurrency level) могут
повлиять на производительность и эффективность ConcurrentHashMap в реальных
сценариях.

19. HashMap
Java Коллекции и стримы

17 - 19 грейд 5 мин 57 раз Свернуть

Как устроен HashMap?

Ответ

17 грейд
HashMap в Java — это структура данных, которая хранит пары "ключ-значение". Внутри она
использует массив, в котором хранятся элементы, распределенные по корзинам (buckets).

https://matrix.o3.ru/trials 13/23
07.10.2024, 15:50 Задачник
Корзина выбирается на основе хэш-кода ключа.

18 грейд
HashMap в Java реализован как массив, в котором элементы (пары "ключ-значение")
хранятся в виде связных списков или деревьев (с Java 8).

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

В Java 8, если длина связанного списка превышает определенное пороговое значение, он


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

19 грейд
Внутреннее устройство HashMap включает в себя массив Node<K,V>[] , где каждый элемент
массива представляет собой корзину (bucket). При добавлении пары "ключ-значение" хэш-
код ключа используется для вычисления индекса корзины.

В Java 8 и позже, если количество элементов в корзине превышает определенный порог


(по умолчанию 8), связанный список преобразуется в красно-черное дерево, что
позволяет уменьшить сложность поиска с O(n) до O(log n).

HashMap также использует методы, такие как resize() для динамического увеличения
размера массива, когда количество элементов превышает определенный коэффициент
загрузки (load factor). При этом элементы перераспределяются в новом массиве, что также
может привести к перехэшированию.

Senior разработчик должен понимать, что HashMap не является потокобезопасной


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

Важно также учитывать, что HashMap может столкнуться с проблемами


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

20. Hashcode
Java Коллекции и стримы

17 - 19 грейд 5 мин 14 раз Свернуть

Какими свойствами должен обладать объект, чтобы быть ключом в хэшмапе?

Ответ

17 грейд
Класс должен переопределить методы hashCode() и equals() так, чтобы можно было
корректно сравнивать ключи и вычислять их хэш-коды.

18 грейд
Чтобы использовать объекты класса в качестве ключей в HashMap , класс должен
корректно переопределять методы hashCode() и equals() .

Метод hashCode() должен возвращать целое число, представляющее хэш-код объекта, и


этот код будет использоваться для определения корзины (bucket) в HashMap .

Метод equals() должен определять логическое равенство двух объектов, чтобы HashMap
мог корректно находить и сравнивать ключи.

Важно, чтобы два объекта, которые считаются равными (по методу equals() ), имели
одинаковые хэш-коды (по методу hashCode() ), иначе HashMap не сможет корректно
работать с этими ключами.

19 грейд
Для использования объектов класса в качестве ключей в HashMap , класс должен
корректно переопределять методы hashCode() и equals() .

Основные требования:

https://matrix.o3.ru/trials 14/23
07.10.2024, 15:50 Задачник
1. Переопределение hashCode() : Этот метод должен возвращать одинаковый хэш-код для
объектов, которые считаются равными по методу equals() . Это необходимо для того,
чтобы объекты распределялись в правильные корзины (buckets) в HashMap .
2. Переопределение equals() : Этот метод должен обеспечивать правильное сравнение
объектов на равенство. Если два объекта равны (по equals() ), они должны иметь
одинаковый хэш-код. Если equals() не переопределен, то сравнение будет
выполняться по умолчанию, используя ссылочное равенство (то есть == ), что может
быть неприемлемо для объектов-сравниваемых ключей.
3. Согласованность hashCode() и equals() : Важно, чтобы эти методы работали
согласованно: если equals() определяет два объекта как равные, то их hashCode()
должен быть одинаковым. В противном случае, объекты могут оказаться в разных
корзинах, и HashMap не сможет их корректно найти или обработать.

Senior разработчик также должен учитывать производительность реализации hashCode() и


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

Будет плюсом если кандидат скажет про высокую кардинальность hashCode и мощность
множества значений.

Дополнительные вопросы

Q: Если кандидат ответил, что "объект должен быть иммутабельным", то стоит спросить
является ли это требование достаточным.

A: Не является. Например, hashCode для одного и того же объекта возвращает разные


значения, зависит от состояния другого объекта / рандома / окружения / etc.

21. ArrayList / LinkedList


Java Коллекции и стримы

17 - 19 грейд 5 мин 81 раз Свернуть

В чем разница между ArrayList и LinkedList?

Какая асимптотика вставки и чтения?

Ответ

17 грейд
ArrayList — это структура данных на основе массива, обеспечивающая быстрый доступ к
элементам по индексу.

LinkedList — это структура данных на основе связного списка, где элементы связаны
друг с другом через ссылки.

ArrayList быстрее для доступа по индексу, а LinkedList — для вставки и удаления


элементов в середине списка.

18 грейд
ArrayList реализован на основе динамического массива, что обеспечивает O(1) доступ к
элементам по индексу, но вставка и удаление элементов в середине списка требуют O(n)
из-за необходимости сдвига элементов.

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

19 грейд
ArrayList - список на массиве, который расширяется в два раза при добавлении элементов.
LinkedList - двусвязный список.

- ArrayList: сложность вставки в начало и середину - O(N), в конец - O(1) (если говорить
про амортизированную сложность).
- LinkedList: сложность вставки в начало и конец - O(1), в середину - O(N).
- Доступ по индексу: ArrayList - O(1), LinkedList - O(N)

https://matrix.o3.ru/trials 15/23
07.10.2024, 15:50 Задачник

22. String interning / Integer cache


Java Знание языка и ООП

18 грейд 5 мин 7 раз Свернуть

Какой результат следующих выражений? Почему?

// 1
Integer a = Integer.valueOf(100);
Integer b = Integer.valueOf(100);
System.out.println(a == b);

// 2
Integer a = Integer.valueOf(1000);
Integer b = Integer.valueOf(1000);
System.out.println(a == b);

// 3
String a = "str";
String b = "str";
System.out.println(a == b);

Ответ

1. true; переменным a и b присваивается одинаковая ссылка, так как для значений в


диапазоне [-128, 127] valueOf использует IntegerCache
2. false; для значений вне диапазона [-128, 127] IntegerCache не используется, и в
переменных будут ссылки на разные объекты
3. true; переменным a и b присваивается одинаковая ссылка, так как string literal
сохраняет строку в пуле (string interning)

23. Дедлок
Java Задачи

19 грейд 15 мин 108 раз Свернуть

Написать код, который всегда с первого раза, гарантированно встаёт в дедлок.

Ответ

import java.util.concurrent.CountDownLatch;

public class GuaranteeDeadlock {

private static final CountDownLatch latch = new CountDownLatch(2);

public static void main(String[] args) throws InterruptedException {


Object a = "object A";
Object b = "object B";

Thread first = new Thread(() -> takeConsequentially(a, b),


"first");
Thread second = new Thread(() -> takeConsequentially(b, a),
"second");

first.start();
second.start();

first.join();
second.join();
}

static void takeConsequentially(Object o1, Object o2) {


try {
synchronized (o1) {
String threadName = Thread.currentThread().getName();

https://matrix.o3.ru/trials 16/23
07.10.2024, 15:50 Задачник
System.out.println(threadName + " thread taken " + o1);
latch.countDown();
latch.await();
synchronized (o2) {
System.out.println(threadName + " thread taken " +
o2);
}
}
} catch (InterruptedException ignored) {
}
}
}

24. Сервер-счётчик
Java Задачи

17 - 20 грейд 15 мин 57 раз Свернуть

Есть теоретическая машина на 100 ядер, на нём запущен HTTP сервер на Java, который
работает на 100 потоках. Всё что делает этот сервер -- считает количество запросов на
него с момента старта сервера.

То есть, условно, есть два метода:

@Singleton
public class Handler {
/**
* Этот метод записывает информацию о каждом разе, когда он был
вызван и ничего не возвращает.
* Этот метод находится под большой нагрузкой, мы хотим иметь
максимальную пропускную способность для него.
*/
@POST("/register_event")
public void registerEvent(Req req) {
//
}

/**
* Этот метод возвращает сколько раз был вызван метод /register_event
с момента старта сервера.
* Этот метод вызывается редко, 1 раз в минуту.
*/
@GET("/events_number")
public int registerEvent(Req req) {
return //...
}
}

Как реализовать сервер-счётчик максимально эффективно с точки зрения пропускной


способности в единицу времени?

Ответ

17 грейд
Самый плохой вариант - synchronized вокруг переменной.

18 грейд
Ещё один плохой вариант: AtomicInteger / AtomicLong . Но при высоком contention (как в
этом примере) и на многосокетных тачках будет работать очень плохо. Возможно, даже
хуже чем synchronized .

19 грейд
Чуть-чуть получше -- решение в акторном стиле: пишем в очередь события, отдельный
поток слушает очередь и обновляет в переменную. Из неё также читаем по запросу к
актору. Но нужно сделать очень грамотную очередь, которая умеет эффективно принимать
из многих потоков данные (Multi-producer/single-consumer). Лучше synchronized, т.к. поток
HTTP сервера не блочится на запись.

https://matrix.o3.ru/trials 17/23
07.10.2024, 15:50 Задачник
Ещё лучше: LongAdder . Имеет лучшую пропускную по сравнению
с AtomicInteger способность за счёт наличия нескольких ячеек, между которым
распределяется запись. При высоком Contention имеет хорошую пропускную способность.

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

Дополнительные вопросы

Этими вариантами задача не ограничена, но это самые популярные.

25. Objects Memory Layout


Java JVM / GC

19 грейд 5 мин 87 раз Свернуть

Сколько байт памяти занимает пустой объект ( new Object() ) в java?

Ответ

Кандидат должен иметь представление о том, из чего состоит markWord и classWord и о


том, что даже пустой объект занимает место. В идеале — сказать, сколько это занимает
места.

26. Number representation


Java Знание языка и ООП

18 грейд 15 мин 59 раз Свернуть

Написать метод, который принимает long и возвращает количество ненулевых битов в


двоичном представлении java

Ответ

Решение может выглядеть например так:

static byte countBits(long number) {


byte result = 0;
for (int i = 0; i < Long.SIZE; i++) {
result += number & 1;
number >>= 1;
}
return result;
}

Желательно, чтобы кандидат использовал битовые операции, не допустил ошибок с


отрицательными числами, знал про two's complement.

27. Кэш и concurrency


Java Задачи

18 грейд 30 мин 200 раз Свернуть

Нужно реализовать "кэш", который хранит лонги по индексу. Размер кэша - 10 элементов.
Реализует два метода: void bulkUpdate(Updater updater) и long[] bulkRead(int[]
indices) .
• bulkUpdate обновляет значения пачкой в текущем состоянии кэша, in-place.
• bulkRead получает пачкой необходимые лонги из кэша по индексам.

Условия:
• Есть N (константа) потоков которые кэш читают.

https://matrix.o3.ru/trials 18/23
07.10.2024, 15:50 Задачник
• Есть 1 поток, который кэш обновляет.
• Читатель должен быть защищён от dirty-read. То есть, если происходит мутация А -> B,
то читатель должен видеть только конечное состояние (A или B), но никогда
промежуточное.
• Чтение должно быть неблокирующим.
• Запись может быть блокирующей.
• Входные данные можно считать всегда влидными (не null; индексы только от 0 до 9
включительно).

(Код на гитлабе с нормальным форматированием: https://gitlab.ozon.ru/-/snippets/3339 )

interface Cache {
//Метод для обновления кэша через мутацию
void bulkUpdate(Updater updater);

//Метод, который принимает индексы для чтения


long[] bulkRead(int[] indices);
}

//Интерфейс, через который пользователи кэша обновляют его


interface Updater {
void updateCurrentState(long[] currentCacheState);
}

Ответ

Решение должно выглядеть примерно так


Copy-on-write (средняя сложность)

(Код на гитлабе с нормальным форматированием: https://gitlab.ozon.ru/-/snippets/3339 )


public class SimpleCache implements Cache {

// Volatile обязателен, без него не соблюдается


// требование к защите от dirty read.
// Пруфы: https://gitlab.ozon.ru/ykornev/cache-jcstress-test/
// Кроме того, формально без volatile нет гарантий,
// что читатель когда либо увидит обновление ссылки.
// Однако, на практике это редко происходит (по крайней мере как
тестировалось на amd64),
// плюс этого явно нет в требованиях.
private volatile long[] cacheArray = new long[10];

public void bulkUpdate(Updater updater) {


long[] prev = Arrays.copyOf(cacheArray, cacheArray.length);
updater.updateCurrentState(prev);
cacheArray = prev;
}

public long[] bulkRead(int[] indices) {


// Здесь обязательно необходимо создать копию ссылки на текущий
массив,
// т.к. ссылка на массив хранимая в поле объекта может измениться в
ходе обхода массива.
long[] current = cacheArray;
return IntStream.of(indices).mapToLong(i -> current[i]).toArray();
}
}

public void main() {


var cache = new SimpleCache();
cache.bulkUpdate(arr -> {
arr[0] = 123;
arr[1] = 456;
});
var cacheValues = cache.bulkRead(new int[]{1, 2});
System.out.println(Arrays.toString(cacheValues));
}

https://matrix.o3.ru/trials 19/23
07.10.2024, 15:50 Задачник
Задача проверяет понимает ли кандидат основы JMM, как работает volatile.

Без volatile или AtomicReference (фактически тоже самое в этом случае) решение не
является корректным. Подробнее: https://gitlab.ozon.ru/ykornev/cache-jcstress-test/

Дополнительные вопросы

Как это потестировать?

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


Затем:
• запустить несколько пишущих и читающих потоков
• или использовать специальные инструменты, например, jcstress (пример:
https://gitlab.ozon.ru/ykornev/cache-jcstress-test/)

28. Очередь и concurrency


Java Задачи

17 - 18 грейд 40 мин 88 раз Свернуть

Реализовать блокирующую очередь (FIFO) заданного размера на основе массива

public class ArrayBlockingQueue {

/**
* Создаёт очередь элементов типа int с заданным максимальным
размером
*/
public ArrayBlockingQueue(int maxSize) {
}

/**
* Добавляет элемент типа int в очередь, ждёт (блокируется) если
очередь заполнена
*/
public void offer(int elt) {
}

/**
* Возвращает и удаляет следующий элемент из очереди, ждёт
(блокируется) если очередь пустая
*/
public int take() {
}
}

Ответ

17 грейд
Простое решение - это каждый раз при take делать `System.arraycopy` таким образом как
бы "смещая" очередь к началу. Нужно уточнить у кандидата какая это сложность, и если
он ответит правильно (O(N)), то спросить можно ли это оптимизировать. Если не сможет -
будем считать это ответом на 17 грейд.

Часто кандидаты делают стек, а не очередь. Если кандидат затрудняется сделать именно
очередь, то считаем это ответом на 17 грейд.

18 грейд
Решение должно выглядеть примерно так:

public class ArrayBlockingQueue {

private final int maxSize;


private final int[] storage;

private int readPos = 0;

https://matrix.o3.ru/trials 20/23
07.10.2024, 15:50 Задачник
private int writePos = 0;
private int currentSize = 0;

public ArrayBlockingQueue(int maxSize) {


this.maxSize = maxSize;
this.storage = new int[maxSize];
}

public void offer(int elt) throws InterruptedException {


synchronized (this) {
while (currentSize == maxSize) {
this.wait();
}
storage[writePos++] = elt;
if (writePos == maxSize) {
writePos = 0;
}
currentSize++;
this.notifyAll();
}
}

public int take() throws InterruptedException {


synchronized (this) {
while (currentSize == 0) {
this.wait();
}
int result = storage[readPos++];
if (readPos == maxSize) {
readPos = 0;
}
currentSize--;
this.notifyAll();
return result;
}
}
}

Задача проверяет умеет ли кандидат работать с concurrency (основные примитивы


синхронизации, synchronized, wait/notify либо Lock+Condition), знает ли некоторые
структуры данных (массив, очередь, ring buffer).
Будет плюсом если кандидат правильно обработает/прокинет выше InterruptedException.

29. Робот
Java Задачи

17 грейд 15 мин 103 раза Свернуть

Есть робот на бесконечной лестнице. У него есть интерфейс. У нас есть ссылка на
интерфейс. В интерфейсе один метод, без аргументов, который возвращает boolean. Если
true — значит он поднялся на одну ступеньку, если false — спустился. Необходимо
написать метод результатом работы которого должно быть то, что робот поднялся на 10
ступенек вверх от своего текущего местоположения.

Ответ

Решение должно выглядеть примерно так

interface Robot {
boolean tryStepUp();
}

public void tenStairsUp(Robot robot) {


int counter = 0;
do {
if (robot.tryStepUp()) {
https://matrix.o3.ru/trials 21/23
07.10.2024, 15:50 Задачник
counter++;
} else {
counter--;
// if (counter == Integer.MIN_VALUE) {
// throw new RuntimeException("Robot is broken");
// } большим плюсом будет такая проверка
}
} while (counter < 10);
}

public void tenStairsUpNoVariables(Robot robot) {


oneStepUp(robot);
oneStepUp(robot);
oneStepUp(robot);
oneStepUp(robot);
oneStepUp(robot);

oneStepUp(robot);
oneStepUp(robot);
oneStepUp(robot);
oneStepUp(robot);
oneStepUp(robot);
}

private void oneStepUp(Robot robot) {


if (!robot.tryStepUp()) {
oneStepUp(robot);
oneStepUp(robot);
}
}

По-хорошему, кандидат не должен использовать break, сравнивать robot.tryStepUp() ==


true, использовать боксовые типы и пр.
После обсудить с ним какие подводные камни скрываются в первом и втором случае.
(Кандидат должен рассказать про type overflow и stack overflow)

Дополнительные вопросы

Сделать то же самое, не используя переменные. Если кандидат испытывает затруднения


— подсказать (попросить поднять на одну ступеньку).

30. Выбор структуры


Java JVM / GC

18 грейд 5 мин 400 раз Свернуть

Какая из структур занимает больше места в памяти: int[1000][10] VS int[10][1000]

Ответ

Кандидат должен понимать, что массив - это объект, он состоит из заголовка (для 64ёх
битной jvm это 16 байт), и полей объекта (4 байта на length массива). Итого, это будет (не
учитываем выравнивание и сжатые ссылки):

(10 * 4 + 4 + 16) * 1000 + 8 * 1000 + 4 + 16 = 68 020


(1000 * 4 + 4 + 16) * 10 + 8 * 10 + 4 + 16 = 40 300

Т.е. первая структура занимает больше места, т.к. в ней больше объектов (массивов) (1001
VS 11).

31. Thread.State
Java Многопоточность

18 грейд 5 мин 99 раз Свернуть

Какие состояния бывают у потока?

https://matrix.o3.ru/trials 22/23
07.10.2024, 15:50 Задачник
Ответ

NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED

Дополнительные вопросы

Q: Чем отличается waiting от blocked?


A: waiting - ожидает notyfy, blocked - ожидает монитор

Q: когда происходит InterruptedException?


A: при вызове interrupt() у запаркованного потока, или при вызове методов wait/sleep у
interrupted потока

32. Алгебра логики


Java Знание языка и ООП

17 грейд 5 мин 26 раз Свернуть

Упростите выражение

if (!odd && !prime || !odd && prime || odd && prime) {

Ответ

if (!odd || prime) {

© 1998 – 2024 ООО «Интернет Решения». Все права защищены

https://matrix.o3.ru/trials 23/23

Вам также может понравиться