Как пройти собеседование по Java: топ вопросов продвинутого уровня
Собеседование на позицию Senior Java Developer — это не просто проверка синтаксиса. Интервьюеры хотят убедиться, что вы понимаете, как работает JVM изнутри, умеете проектировать многопоточные системы и знаете тонкости сборки мусора. В этой статье мы разберем самые частые и сложные вопросы, которые помогут вам уверенно пройти техническое интервью.
1. Многопоточность и модель памяти Java (JMM)
Это одна из самых объемных тем. Интервьюеры проверяют, понимаете ли вы, как потоки взаимодействуют через общую память, и какие проблемы могут возникнуть.
Вопрос: В чем разница между volatile и synchronized?
Ответ: volatile гарантирует видимость изменений для всех потоков, но не обеспечивает атомарность. synchronized гарантирует и видимость, и атомарность (блокирует монитор).
// Пример использования volatile
public class VolatileExample {
private volatile boolean running = true;
public void stop() {
running = false; // Изменение сразу видно другим потокам
}
public void run() {
while (running) {
// выполнение работы
}
}
}
Вопрос: Что такое happens-before в JMM?
Ответ: Это отношение частичного порядка, гарантирующее, что действия в одном потоке будут видны другому. Например, запись в volatile переменную создает happens-before с последующим чтением этой переменной другим потоком. Также happens-before возникает при входе/выходе из synchronized блока.
Вопрос: Как устроен ConcurrentHashMap?
Ответ: В Java 8+ ConcurrentHashMap использует сегментирование на уровне бакетов (buckets). Вместо блокировки всей таблицы, блокируется только конкретная корзина (при коллизиях). Для операций чтения блокировки не используются — используется volatile чтение. При высоком уровне конкуренции внутренние структуры могут перестраиваться (например, дерево вместо списка).
// Пример ConcurrentHashMap
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key", 1);
Integer value = map.get("key"); // Без блокировки чтения
2. Сборка мусора и оптимизация GC
Вопросы про Garbage Collector (GC) — обязательны для Senior-позиций. Вам нужно знать не только типы GC, но и как настраивать их под нагрузку.
Вопрос: Какие есть основные типы GC в HotSpot JVM?
Ответ: Основные сборщики:
- Serial GC — однопоточный, для клиентских приложений.
- Parallel GC (Throughput) — многопоточный, ориентирован на пропускную способность.
- G1 GC (Garbage First) — дефолтный с Java 9, разделяет кучу на регионы, минимизирует паузы.
- ZGC и Shenandoah — низколатентные сборщики с паузами менее 10 мс.
Вопрос: Что такое Stop-The-World пауза?
Ответ: Это момент, когда все потоки приложения приостанавливаются, чтобы GC мог выполнить свою работу. Длительные STW паузы критичны для real-time систем. G1 GC старается минимизировать их, выполняя сборку параллельно и инкрементально.
Вопрос: Как выявить утечку памяти в Java?
Ответ: Используйте профилировщики (VisualVM, JProfiler). Следите за ростом heap dump. Типичные причины утечек: неосвобожденные статические коллекции, неправильная реализация equals/hashCode в HashMap, слушатели, которые не отписываются.
// Пример утечки: статическая коллекция
public class LeakExample {
private static List<byte[]> cache = new ArrayList<>();
public void addData() {
cache.add(new byte[1024 * 1024]); // Утечка, если не чистить
}
}
3. Паттерны проектирования и архитектура
Продвинутый уровень подразумевает знание не только GoF паттернов, но и умение применять их в контексте Java.
Вопрос: Как реализовать потокобезопасный Singleton?
Ответ: Лучший способ — использовать enum или double-checked locking с volatile.
// Double-checked locking
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Вопрос: В чем отличие Strategy от State?
Ответ: Strategy инкапсулирует алгоритм и позволяет подменять его на лету. State — это паттерн, где объект меняет свое поведение при изменении внутреннего состояния. В Strategy клиент выбирает стратегию, в State — состояние управляет переходом.
Вопрос: Когда использовать Dependency Injection?
Ответ: DI обязателен для тестируемости и слабой связанности. В Spring это делается через конструктор. Никогда не используйте Field Injection — это нарушает принцип инверсии контроля и усложняет тестирование.
// Правильный DI через конструктор
@Service
public class OrderService {
private final PaymentGateway paymentGateway;
public OrderService(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
}
4. Коллекции и работа с памятью
Интервьюеры проверяют, как вы выбираете структуры данных для конкретных задач.
Вопрос: Когда использовать ArrayList, а когда LinkedList?
Ответ: ArrayList — когда нужен быстрый доступ по индексу и операции вставки/удаления в конце. LinkedList — когда часто вставляете/удаляете в середине списка, но доступ по индексу медленный (O(n)).
Вопрос: Как работает HashMap при коллизиях?
Ответ: В Java 8+ при превышении порога (8 элементов в корзине) список преобразуется в красно-черное дерево. Это