← Назад к вопросам

Можно ли в synchronized указать какую часть нужно синхронизировать?

2.0 Middle🔥 161 комментариев
#Многопоточность и асинхронность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Можно ли в synchronized указать какую часть нужно синхронизировать?

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

Два способа использования synchronized

  1. Синхронизация всего метода (на уровне метода).
  2. Синхронизация блока кода (на уровне объекта или класса).

Синхронизация всего метода

При объявлении метода с synchronized весь его код становится синхронизированным. В качестве объекта-монитора (то, на котором происходит блокировка) используется:

  • Для нестатических методов — объект this (текущий экземпляр класса).
  • Для статических методов — объект класса (Class).
public class Counter {
    private int value = 0;
    
    // Синхронизация всего метода на объекте 'this'
    public synchronized void increment() {
        value++;
    }
    
    // Синхронизация всего статического метода на объекте класса Counter.class
    public static synchronized void staticIncrement() {
        // статическая логика
    }
}

Синхронизация блока кода

Это более гибкий подход. Используется конструкция synchronized(object) { ... }, где object — это объект-монитор, на котором происходит блокировка. Это позволяет:

  • Синхронизировать только критическую секцию, а не весь метод.
  • Использовать разные мониторы для разных участков кода внутри одного метода.
  • Снизить время блокировки, позволяя другим потокам работать с несинхронизированными частями метода.
public class FineGrainedSync {
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();
    private int counter1 = 0;
    private int counter2 = 0;
    
    public void updateCounters() {
        // Независимые операции можно выполнять параллельно
        doSomeNonCriticalWork();
        
        // Синхронизируем только увеличение counter1 на lock1
        synchronized(lock1) {
            counter1++;
        }
        
        // Синхронизируем только увеличение counter2 на lock2
        synchronized(lock2) {
            counter2++;
        }
        
        doMoreNonCriticalWork();
    }
}

Важные особенности и рекомендации

  • Объект-монитор: Для блоков синхронизации можно использовать любой объект, но обычно применяют:

    • Специально созданные private объекты (private final Object lock = new Object()).
    • Сам класс (ClassName.class) для статических данных.
    • this для синхронизации на текущем экземпляре.
  • Производительность: Синхронизация блока кода часто более эффективна, так как сокращает время, которое поток держит монитор. Это уменьшает contention (конкуренцию) и повышает throughput (производительность) системы.

  • Читаемость и безопасность: Создание отдельного объекта для блокировки (как в примере выше) — хорошая практика. Это предотвращает случайные блокировки на публичных объектах и делает потокобезопасность более явной.

  • Пример с коллекциями: Типичный случай — работа с ArrayList (не синхронизирован по умолчанию).

public class SyncListExample {
    private List<String> list = new ArrayList<>();
    private final Object listLock = new Object();
    
    public void addItem(String item) {
        // Синхронизируем только операцию добавления
        synchronized(listLock) {
            list.add(item);
        }
        // Остальной код метода выполняется без блокировки
        log("Item added: " + item);
    }
}

Итог

Ключевое слово synchronized предоставляет механизм для синхронизации как методов целиком, так и произвольных блоков кода на определенных объектах-мониторах. Синхронизация блоков — более точный инструмент, позволяющий оптимизировать многопоточное выполнение, минимизировать области блокировки и использовать разные мониторы для разных ресурсов. Это фундаментальная техника для написания эффективных и безопасных многопоточных приложений в Java и, соответственно, в Android (где, однако, чаще используются более современные механизмы из java.util.concurrent и Kotlin Coroutines).

Можно ли в synchronized указать какую часть нужно синхронизировать? | PrepBro