Что выступает монитором для статического synchronized метода в Java?

Ответ

Монитором для статического 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). Одна блокировка на всех, хоть ты десять экземпляров создай.

Это, кстати, охуенно продумано, чтобы операции над статическими данными не ебались с операциями над экземплярами, и наоборот. Чистота, блядь, и порядок!