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

«В каких случаях синхронизированный блок предпочтительнее синхронизированного метода в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Использование синхронизированного блока (synchronized(object) { ... }) вместо синхронизированного метода (public synchronized void method()) дает больше гибкости и может повысить производительность.

Ключевые преимущества синхронизированного блока:

  1. Тонкая настройка блокировки (Fine-grained locking): Блокируется только критическая секция кода, а не весь метод. Остальной код метода может выполняться параллельно.
  2. Контроль над объектом-монитором: Можно использовать отдельный, приватный объект для блокировки вместо блокировки всего экземпляра класса (this). Это уменьшает contention (конкуренцию) между потоками.
  3. Повышение производительности: Меньший объем синхронизированного кода сокращает время, в течение которого потоки ожидают друг друга.

Пример:

public class Counter {
    private int count = 0;
    private final Object lock = new Object(); // Специальный объект для блокировки

    public void increment() {
        // Несинхронизированная операция (например, логирование)
        System.out.println("Подготовка к инкременту");

        synchronized (lock) { // Блокируется только объект 'lock', а не весь 'this'
            // Критическая секция
            count++;
        }
        // Дальнейший несинхронизированный код
    }
}

Когда использовать метод? Синхронизированный метод уместен, когда весь метод является критической секцией и достаточно блокировки на экземпляре (this) или классе (для статических методов).