Подтвердить что ты не робот

Какой смысл делать одиночный экземпляр volatile при использовании двойной блокировки?

private volatile static Singleton uniqueInstance

В одноэлементном режиме при использовании метода двойной блокировки для синхронизации почему единственный экземпляр, объявленный как изменчивый? Могу ли я достичь такой же функциональности, не объявляя ее нестабильной?

4b9b3361

Ответ 1

Без volatile код работает некорректно с несколькими потоками.

Из Википедии Двойная проверка блокировки:

По состоянию на J2SE 5.0 эта проблема исправлена. Теперь ключевое слово volatile гарантирует, что несколько потоков обрабатывают экземпляр singleton правильно. Эта новая идиома описана в Декларация с двойной проверкой блокировки:

// Works with acquire/release semantics for volatile
// Broken under Java 1.4 and earlier semantics for volatile
class Foo {
    private volatile Helper helper = null;
    public Helper getHelper() {
        Helper result = helper;
        if (result == null) {
            synchronized(this) {
                result = helper;
                if (result == null) {
                    helper = result = new Helper();
                }
            }
        }
        return result;
    }

    // other functions and members...
}

В общем, вам следует избегать блокировки с двойной проверкой, если это возможно, так как это трудно сделать правильно, и если вы ошибетесь, это может быть трудно найти ошибку. Вместо этого попробуйте этот простой подход:

Если вспомогательный объект является статическим (по одному для каждого загрузчика классов), альтернативой является инициализация по требованию владельца идиомы

// Correct lazy initialization in Java 
@ThreadSafe
class Foo {
    private static class HelperHolder {
       public static Helper helper = new Helper();
    }

    public static Helper getHelper() {
        return HelperHolder.helper;
    }
}

Ответ 2

volatile предотвращает переупорядочение записей в памяти, что делает невозможным чтение других потоков неинициализированных полей вашего синглтона с помощью одноточечного указателя.

Рассмотрим эту ситуацию: поток A обнаруживает, что uniqueInstance == null, блокирует, подтверждает, что он все еще null, и вызывает singleton constructor. Конструктор делает запись в член XYZ внутри Singleton и возвращает. Thread A теперь записывает ссылку на вновь созданный синглтон в uniqueInstance и готовится к его блокировке.

Так же, как поток A готов к выпуску блокировки, поток B приходит и обнаруживает, что uniqueInstance не null. Тема B обращается к uniqueInstance.XYZ, думая, что она была инициализирована, но из-за того, что CPU переупорядочил записи, данные, которые поток A записал в XYZ, не были видимыми для потока B. Следовательно, поток B видит неправильный значение внутри XYZ, что неверно.

Когда вы отмечаете uniqueInstance volatile, вставляется барьер памяти. Все записи, инициированные до uniqueInstance, будут завершены до изменения uniqueInstance, предотвращая описанную выше ситуацию переупорядочения.

Ответ 3

Чтобы избежать использования двойной блокировки или летучих я использую следующие

enum Singleton {
     INSTANCE;
}

Создание экземпляра прост, ленив загружен и потокобезопасен.

Ответ 4

Вы можете использовать следующий код:

private static Singleton uniqueInstance;

public static synchronized Singleton getInstance(){
    if(uniqueInstance == null){
        uniqueInstance = new Singleton();
    }
    return uniqueInstance
}

Ответ 5

Запись в поле volatile произойдет до любой операции чтения. Ниже приведен пример кода для лучшего понимания:

private static volatile ResourceService resourceInstance;
//lazy Initialiaztion
public static ResourceService getInstance () {
    if (resourceInstance == null) { // first check
        synchronized(ResourceService.class) {
            if (resourceInstance == null) { // double check
                // creating instance of ResourceService for only one time
                resourceInstance = new ResourceService ();                    
            }
        }
    }
    return resourceInstance;
}

Эта ссылка может вам помочь http://javarevisited.blogspot.com/2011/06/volatile-keyword-java-example-tutorial.html