Что если мы используем только внешнюю проверку на нуль в шаблоне синглтона двойной проверки? - PullRequest
0 голосов
/ 06 июля 2019

Вопрос 1. Почему в одноэлементном шаблоне для многопоточности нам нужны две проверки на ноль? Что если мы используем только внешний чек?

    if (instance == null) {
        synchronized (ABC.class) {

            // What if we remove this check?
            if (instance == null) {
                instance = new ABC();
            }
    }

Вопрос 2: В чем разница между следующим:

1: непосредственное использование имени класса в synchronized ()

    public ABC getInstance() {
        if (instance == null) {
            // Difference here
            synchronized (ABC.class) {
                if (instance == null) {
                    instance = new ABC();
                }
            }
         }
         return instance;
    }

2: Использование статического финального объекта внутри synchronized ()

    private static final Object LOCK = new Object();
    .
    .
    public ABC getInstance() {
        if (instance == null) {

             // Difference here
             synchronized (LOCK) {
                if (instance == null) {
                    instance = new ABC();
                }
             }
         }
         return instance;
    }

3: использование new Object () внутри synchronized ()

    if (instance == null) {
    // Difference here
         synchronized (new Object()) {
            if (instance == null) {
                instance = new ABC();
            }
        }
     }

1 Ответ

0 голосов
/ 06 июля 2019
  1. Снятие внутренней проверки на нуль может привести к состоянию гонки.Представьте себе следующий сценарий: два потока пытаются получить экземпляр вашего объекта в одно и то же время, поэтому они оба проверяют, равен ли экземпляр значение null, и получают истинный ответ, поэтому оба потока будут пытаться создать экземпляр вашего объекта.Поскольку этот код синхронизирован, один из этих потоков войдет в синхронизированный блок кода, в то время как другой ожидает снятия блокировки.Когда первый поток завершит создание экземпляра и возврат экземпляра вашего объекта, блокировка будет снята, а второй поток выполнит синхронизированный блок, поэтому он создаст новый экземпляр и вернет его, потому что он не знает, что он был создан ранее.пока он ждал своей очереди.
  2. Использование класса в качестве аргумента в синхронизированном генерирует статическую блокировку.Это означает, что все экземпляры класса будут совместно использовать блокировку.
  3. Использование объекта в качестве аргумента для синхронизации полезно, если вы хотите заблокировать синхронизированный блок с конкретным объектом вместо класса или этого,Это позволяет вам иметь разные блоки кода, используя разные блокировки в одном и том же классе.Например:

    Object o1 = new Object();
    Object o2 = new Object();
    synchronized(o1) {
        //your synchronized block
     }
    
    synchronized(o2){
        //other synchronized block
    }
    

В предыдущем примере кода block1 и block2 могут выполняться одновременно разными потоками, поскольку они используют разные объекты блокировки.Если бы вы использовали одну и ту же блокировку для обоих блоков кода (IE класс), блок 1 будет блокироваться до тех пор, пока block2 не завершит свое выполнение, и наоборот.

...