ПРИХОДИТЕ УЧИТЬСЯ НОВОЙ ПРОФЕССИИ ЛЕТОМ СО СКИДКОЙ ДО 70%Забронировать скидку

Синхронизация в Java: блокировка на уровне объекта или метода

Пройдите тест, узнайте какой профессии подходите и получите бесплатную карьерную консультацию
В конце подарим скидку до 55% на обучение
Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

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

Вот компактный пример:

Java
Скопировать код
public synchronized void syncInstanceMethod() {
    // Здесь можно представить VIP-клуб, где единомоментно пребывать может лишь один поток на весь объект
}

Контрастно этому, статические синхронизированные методы блокируют объект класса (ClassName.class), что вынуждает методы данного класса выполняться последовательно, исключая параллельное исполнение в разных потоках.

Вот пример для визуализации:

Java
Скопировать код
public static synchronized void syncStaticMethod() {
    // Здесь можно увидеть аналогию со специальным мероприятием, в которое пускают лишь один поток на все экземпляры класса
}
Пройдите тест и узнайте подходит ли вам сфера IT
Пройти тест

Обзор и разъяснение задействованных механизмов

Гибкость синхронизированных блоков

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

Java
Скопировать код
public void methodWithSynchronizedBlock(Object lock) {
    // Пока отдыхаем...
    synchronized(lock) {
        // Здесь идёт критическая фаза, куда может войти только один поток, имеющий подходящий ключ
    }
    // Снова небольшой отдых...
}

Преимущества атомарных переменных

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

Java
Скопировать код
private AtomicInteger atomicCount = new AtomicInteger(0);

public void increment() {
    atomicCount.incrementAndGet(); // Атомарно увеличиваем значение на 1, словно берем печеньку из общей коробки
}

Как правильно выбрать инструмент?

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

Визуализация

Можно представлять оператор synchronized в Java как личного охранника, находящегося у двери метода или охраняющего целый объект:

Markdown
Скопировать код
🔒 Синхронизированный метод:
| Метод   |    Охранник   |
|---------|:-------------:|
| method1 |       🛡️      |
| method2 |       🛡️      |
| method3 |               |
# У каждого синхронизированного метода есть свой охранник, как в VIP-зале.

🔐 Синхронизация на объекте:
|  Объект |  Охранник здания    |
|---------|:-------------------:|
| obj1    |          🛡️        |
# Здесь охранник стоит на защите всего объекта, как вышибалы в клубе.

Каждый синхронизированный метод функционирует как отдельный замок, а синхронизация на уровне объекта ставит одного охранника на защиту всей территории.

Выбор между synchronized и атомарными переменными

Снижение затрат на обеспечение потокобезопасности

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

Обеспечение консистентности данных с synchronized

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

Избегание проблем с производительностью

Чрезмерное использование synchronized может негативно повлиять на производительность приложения. Рекомендуется обходиться с этим инструментом разумно.

Понимание области действия блокировок и видимости памяти

Как выбрать между синхронизацией на уровне экземпляра и класса

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

Влияние на консистентность памяти

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

Точное управление блокировками

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

Полезные материалы

  1. Synchronized Methods (The Java™ Tutorials > Essential Java Classes > Concurrency) — Официальная документация Oracle о синхронизированных методах в Java.
  2. java – What does 'synchronized' mean? – Stack Overflow — Обсуждение концепции synchronized на Stack Overflow.
  3. Synchronization in Java – GeeksforGeeks — Краткий обзор синхронизации и блокировки в Java от GeeksforGeeks.
  4. Chapter 17. Threads and Locks — Официальная спецификация Java по вопросам управления потоками и блокировками.
  5. Java – Thread Synchronization — Обзор применения инструкции synchronized в Java от Tutorialspoint.