Что будет, если 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), а не по экземпляру. Это делает метод глобально синхронизированным для всех потоков, независимо от того, с какого объекта вызывается. Полезно, если вы работаете с общими ресурсами на уровне класса, но требует осторожности из-за риска блокировок и потери производительности.