Как работает функция синхронизации в Java? - PullRequest
11 голосов
/ 05 июля 2011

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

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

Ответы [ 7 ]

14 голосов
/ 05 июля 2011

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

5 голосов
/ 05 июля 2011

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

Ключевое слово java synchronized разрешает следующее:

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

Вот пример синглтона:

public class Singleton {
    private Singleton INSTANCE;

    private Singleton() {
    }

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

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

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

1 голос
/ 05 июля 2011

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

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

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

1 голос
/ 05 июля 2011

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

synchronized(someObject)
{
   someCode();
}

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

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

0 голосов
/ 26 апреля 2012

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

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;
     }
 } 
0 голосов
/ 05 июля 2011

Вы пробовали Google (Java Deadlock) ?Первый результат таков: http://download.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

Там вы можете видеть, что при synchronized по-прежнему возникают взаимоблокировки, поскольку синхронизация не предназначена для предотвращения их возникновения.

0 голосов
/ 05 июля 2011

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

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

...