Что будет, если synchronized повесить на статический метод?

Если synchronized повесить на статический метод в Java, то блокировка будет происходить на уровне класса, а не конкретного объекта.

То есть:

  • В случае нестатического метода synchronized, блокировка идёт по экземпляру (this).

  • В случае статического метода synchronized, блокировка идёт по объекту класса Class<?>, то есть MyClass.class.

🔧 Что это значит на практике?

📌 Пример:

public class Counter {
public static synchronized void incrementStatic() {
// блокировка по Counter.class
}
public synchronized void incrementInstance() {
// блокировка по this (экземпляру)
}
}

Поведение:

  • Все потоки, вызывающие incrementStatic(), будут синхронизированы по одному замку: Counter.class.

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

Демонстрация

Thread t1 = new Thread(() -> Counter.incrementStatic());
Thread t2 = new Thread(() -> Counter.incrementStatic());
t1.start();
t2.start();

Обе нити будут выполняться строго по очереди, потому что синхронизируются по одному и тому же объекту Counter.class.

Но:

Counter c1 = new Counter();
Counter c2 = new Counter();
Thread t1 = new Thread(() -> c1.incrementInstance());
Thread t2 = new Thread(() -> c2.incrementInstance());

Здесь нет взаимной блокировки — разные объекты c1 и c2.

📍 Зачем синхронизировать статические методы?

  • Когда нужно защитить статические поля от одновременного доступа.

  • Когда логика не привязана к конкретному экземпляру, а к классу в целом.

  • Когда есть глобальное состояние (например, singleton или кэш на уровне класса).

⚠️ Подводные камни

  • Статическая синхронизация блокирует все потоки, работающие с этим классом. Это может стать узким местом, если метод используется часто.

  • Если в проекте используется ClassLoader, важно понимать, что блокировка идёт по конкретному объекту Class, который может быть разным для одного и того же класса, загруженного разными загрузчиками.

Вывод

Если synchronized применён к статическому методу, он синхронизируется по объекту Class (например, MyClass.class), а не по экземпляру. Это делает метод глобально синхронизированным для всех потоков, независимо от того, с какого объекта вызывается. Полезно, если вы работаете с общими ресурсами на уровне класса, но требует осторожности из-за риска блокировок и потери производительности.