На одном из собеседований мне попался вопрос: “Что будет являться монитором для блока кода, помеченного сразу двумя аннотациями @Synchronized и @JvmStatic в Котлин?”. В данной статье рассмотрим, для чего используются данные аннотации и каким будет результат при их одновременном использовании. Аннотация @Synchronized в Kotlin является аннотацией для методов и блоков кода, которая обеспечивает синхронизацию доступа к ним между потоками. Когда метод или блок кода помечены аннотацией @Synchronized, только один поток может получить право их выполнения в определенный момент времени, остальные потоки будут ожидать освобождения монитора, прежде чем получить доступ. Это позволяет избежать состояния гонки и обеспечить правильное выполнение кода в многопоточной среде.

Пример обычного использования аннотации @Synchronized:

class Example {
    @Synchronized
    fun synchronizedMethod() {
        // Код, требующий синхронизации
    }
}

В этом примере метод synchronizedMethod() будет доступен только одному потоку в определенный момент времени. Если другой поток попытается вызвать этот метод, пока первый поток выполняет его, он будет ожидать, пока монитор не будет освобожден.

Аннотация @JvmStatic в Kotlin указывает компилятору, что функция или свойство должны быть статическими в Java-коде после компиляции. Когда мы используем @JvmStatic перед функцией или свойством в объекте- компаньоне или внутри объекта, компилятор Kotlin создает соответствующий статический элемент в Java-коде. Это позволяет вызывать этот элемент напрямую из Java-кода, без необходимости ссылаться на экземпляр класса или объекта.

Вот пример использования @JvmStatic:

class MyClass {
    
    companion object {
        @JvmStatic
        fun myStaticFunction() {
            // ... 
        }
    }
}

После компиляции, функция myStaticFunction() будет доступна в Java-коде как статическая функция класса MyClass. Теперь посмотрим, что произойдет, если использовать эти две аннотации вместе:

class Example {

    companion object {  
        @Synchronized
        @JvmStatic
        fun synchronizedStaticMethod() {
            //...
        }
    }
}

В этом примере статический метод synchronizedStaticMethod() также будет доступен только одному потоку в определенный момент времени. Остальные потоки будут ожидать освобождения монитора, чтобы получить доступ к методу. В данном случае объектом синхронизации будет выступать сам класс Example, так как в Java имеется механизм синхронизации по классу. То есть, в Java этот код выглядел бы следующим образом:

class Example {

    public static void synchronizedStaticMethod() {
        synchronized(Example.class){
            //...
        }
    }
}

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