Как работает функция синхронизации в java?

Так как я начал программировать на Java, мне это интересно (около года или двух). В C мы должны знать другой метод, чтобы правильно избежать взаимоблокировки между потоком, и, следовательно, выбор между методом синхронизации намного больше.

А как насчет Java? Когда мы синхронизируем, как он избегает помещать поток в тупик? Как это работает внутри страны? Отключен ли тупик, потому что мы синхронизировались на более высоком уровне, чем на C (или С++)? Любая документация о тупике и синхронизации в java?

Ответ 1

Под капотом он использует два кода opcodes monitorenter и monitorexit на уровне байтового кода, который устанавливает/освобождает блокировки на ссылке на объект на глобальном уровне JVM. Я настоятельно рекомендую вам прочитать Как виртуальная машина Java выполняет синхронизацию потоков.

Ответ 2

Основная проблема (-и), с которой мы встречаемся с многопоточным кодом, - это совместное использование данных, и я согласен с тем, что это процесс параллельного вычисления, и это происходит "по-разному", что во время параллализованной обработки потоки нуждаются в доступе для чтения/записи на общих данных.

Ключевое слово java synchronized позволяет следующее:

Он сообщает JVM о блокировке на мониторе объекта или части синхронизированного кода, который дает ему эксклюзивный доступ к этой части кода или объекта.

Вот пример Singleton:

public class Singleton {
    private Singleton INSTANCE;

    private Singleton() {
    }

    public Singleton getInstance() {
        if (null == INSTANCE) {
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}

Этот Singleton не является потокобезопасным, если поток пытается получить экземпляр, в то время как другой также пытается сделать то же самое (состояние гонки), может случиться так, что до этого номер потока один заканчивает создание экземпляра второй уже имеет доступ к методу getInstance() и создал свой собственный экземпляр Singleton, что означает, что в момент времени T мы должны иметь два экземпляра Singleton (называемый в данный момент мультитоном).

Чтобы решить эту проблему, мы должны синхронизировать творческое поведение синглтона, это может быть сделано с помощью ключевого слова synchronized над оператором if самого INSTANCE:

public class Singleton {
    private Singleton INSTANCE;

    private Singleton() {
    }

    public Singleton getInstance() {
        synchronized (Singleton.class) {
            if (null == INSTANCE) {
                synchronized(Singleton.class) {
                   Singleton inst = new Singleton();
                   INSTANCE = inst;   
                }
            }
        }
        return INSTANCE;
    }
}

В результате, когда первый поток запрашивает экземпляр Singleton и во время создания, JVM помещает блокировку на мониторе INSTANCE, лишая доступ к INSTANCE, пока нить не завершит свой запрос.

Существуют и другие способы достижения этой цели, цитированная ранее книга является отличным источником обучения, javadoc также.

Ответ 3

Синхронизация на Java гораздо проще, чем в C. Синтаксически это проще, потому что все, что вам нужно сделать для мьютекса, - объявить метод как синхронизированный или использовать

synchronized(someObject)
{
   someCode();
}

В то время как в C/С++ вы должны использовать функции, зависящие от операционной системы, для использования мьютекса, или вам нужно использовать библиотеку Boost.

Но подводные камни о тупике все в основном такие же, как на любом языке.

Ответ 4

Краткие ответы:

  • synchronized и блоки lock используют монитор, который блокирует семафор заблокированного объекта в течение всего метода или блока.

  • Сам язык Java не предотвращает взаимоблокировки. Это вам, как программисту, чтобы гарантировать, что объекты заблокированы/разблокированы в правильном порядке, чтобы предотвратить конфликт.

Ответ 5

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

Прочитайте учебник по Java о concurrency. И если вы хотите продолжать учиться, прочитайте Java concurrency на практике.

Ответ 7

Я вижу проблему с Singleton выше. Я думаю, что этот класс никогда не будет создан. Пожалуйста, рассмотрите ниже код.

public class Singleton {
     private static Singleton INSTANCE;
     private Singleton() {     }
     public static Singleton getInstance() {
         synchronized (Singleton.class) {
             if (null == INSTANCE) {
                 synchronized(Singleton.class) {
                    Singleton inst = new Singleton();
                    INSTANCE = inst;
                    }
             }
         }
         return INSTANCE;
     }
 }