Ответ
Монитором для статического synchronized метода является объект класса Class, соответствующий классу, в котором объявлен метод.
Ключевые моменты:
- В JVM каждый загруженный класс представлен объектом типа
java.lang.Class. - Статические
synchronizedметоды используют монитор этого объектаClass, а не монитор какого-либо экземпляра. - Это означает, что блокировка распространяется на все статические synchronized методы класса и все
synchronized(ClassName.class)блоки для всех экземпляров приложения.
Пример:
public class Logger {
private static List<String> logEntries = new ArrayList<>();
// Монитором является Logger.class
public static synchronized void log(String message) {
logEntries.add(message);
}
// Этот метод использует ТОТ ЖЕ монитор (Logger.class)
public static synchronized void clearLog() {
logEntries.clear();
}
}
// В разных потоках:
Logger.log("Start"); // Поток 1 захватывает монитор Logger.class
// Поток 2 будет ждать здесь, если попытается вызвать Logger.clearLog()
Эквивалентная запись с явной блокировкой:
public static void log(String message) {
synchronized(Logger.class) { // Явная блокировка по объекту Class
logEntries.add(message);
}
}
Важное отличие от нестатических методов:
- Нестатический метод:
synchronized→ блокировка поthis(экземпляру). - Статический метод:
synchronized→ блокировка поClassName.class.
Это разделение предотвращает нежелательные блокировки между операциями над экземплярами и статическими данными.
Ответ 18+ 🔞
А, слушай, вот эта тема про статик синхронизацию — это вообще отдельный цирк, блядь. Все думают: "ой, синхронизированный метод, ну значит по this блокировка". А тут, сука, подвох!
Когда метод статический, то this — это пиздец, его просто нету, он в отпуске! Монитором тут служит не какая-то там инстанция, а сам объект класса Class, который в JVM представляет этот твой класс. Да, вот эта самая хуйня, которую ты через Logger.class получаешь.
Короче, запомни раз и нахуй:
- В виртуальной машине каждый класс, который загрузили, — это объект типа
java.lang.Class. - Все статические
synchronizedметоды цепляются за монитор этого самого объектаClass. - Итог: если ты зашёл в один такой метод, то все остальные статические синхронизированные методы этого класса и все блоки
synchronized(ИмяКласса.class)по всей программе — будут ждать, как лохи! Вне зависимости от того, сколько экземпляров создано.
Смотри, как это выглядит в коде:
public class Logger {
private static List<String> logEntries = new ArrayList<>();
// Монитором является Logger.class, блядь!
public static synchronized void log(String message) {
logEntries.add(message);
}
// И этот тоже висит на том же самом мониторе — Logger.class
public static synchronized void clearLog() {
logEntries.clear();
}
}
// А теперь представь два потока:
Logger.log("Start"); // Поток 1 схватил монитор Logger.class
// Если Поток 2 в этот момент вызовет Logger.clearLog() — сиди, жди, мудак, пока первый не отпустит!
И это, сука, можно записать явно, чтобы мозг не выебывался:
public static void log(String message) {
synchronized(Logger.class) { // Да, вот так, явно по объекту Class
logEntries.add(message);
}
}
И главное отличие, чтобы в жопу не запутаться:
- Обычный (нестатический) метод с
synchronized— блокировка идёт по конкретному экземпляру (this). Два разных объекта — две независимые блокировки. - Статический метод с
synchronized— блокировка идёт по всему классу (ClassName.class). Одна блокировка на всех, хоть ты десять экземпляров создай.
Это, кстати, охуенно продумано, чтобы операции над статическими данными не ебались с операциями над экземплярами, и наоборот. Чистота, блядь, и порядок!