Синглтон с использованием атомарного неблокирующего метода против синхронизированного - PullRequest
0 голосов
/ 14 октября 2019

Я пытался использовать Non Blocking Atomic Boolean API для создания одноэлементного объекта вместо синхронизированного.

У меня есть 2 реализации

  1. с помощью двойной блокировки и синхронизированного ключевого слова
  2. Через Atomic Non Blocking Call

Я считаю, что мы можем иметь надежную и лучшую реализацию через Atomic, чем синхронизированную. Пожалуйста, предложите, если я ошибаюсь. Также выполняет некоторый базовый тест производительности, который предпочитает атомарную реализацию перед синхронизированными.

Поддерживает

// Lazy Initialization
// Thread-safe
// Performance improvement for corresponding calls, once the object is created

public class Singleton {
    private static Singleton instance;

    static final AtomicBoolean isInitialized = new AtomicBoolean(false);

    private Singleton() {
        // private constructor //Thread.sleep(10)

    }

    // 1st Implementation
    // Via Double Locking and Synchronized
    public static Singleton getInstance() {
        if (instance == null) {
            // synchronized block to remove overhead
            synchronized (Singleton.class) {
                if (instance == null) {
                    // if instance is null, initialize
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    // 2nd Implementation + Not ThreadSafe with Null Objects.
    // Via Atomic Non Blocking Method and avoiding Synchronized
    public static Singleton getInstanceViaAtomic() {
        if (instance != null)
            return instance;

        if (isInitialized.compareAndSet(false, true)) {
            return instance = new Singleton();
        }
        return instance;
    }

}

Обновление @Kayaman правильно определил, что вышеупомянутый impl не является поточно-ориентированным. Я исправил в следующем.

// 2nd Implementation + Thread Safe
// Via Atomic Non Blocking Method and avoiding Synchronized
public static Singleton getInstanceViaAtomic() throws InterruptedException {
    while(instance == null) {
        if (isInitialized.compareAndSet(false, true)) {
            instance = new Singleton();
        }
    }
    return instance;

}

1 Ответ

1 голос
/ 14 октября 2019

2-я реализация не является поточно-ориентированной. Простой способ показать это - поместить Thread.sleep(10); (или более) в конструктор Singleton.

. Это заставит первый поток установить isInitialized в true (в то время как instanceравно нулю), затем вызовите new Singleton();.

Другой поток увидит instance как null, он не войдет в блок if, потому что логическое значение теперь true, затемвернет instance, что является нулем.

Таким образом, условие гонки заканчивается на NullPointerException.

Если бы мы заставили это решение перевести в рабочее, оно должно было бы использоватьspinlock и может быть что-то вроде этого (это утренний код, поэтому дайте мне знать, если что-то странное):

public static Singleton getInstance() {

    // Fast-path when singleton already constructed
    if(instance != null)
        return instance;

    // Spinlock lets the first thread through, others will spin
    while(instance == null && !isInitialized.compareAndSet(false, true))
        ;

    // First thread creates the singleton, spun threads will ignore
    if(instance == null)
        instance = new Singleton();

    return instance;
}

также instance должно быть volatile для обеспечения видимости.

Первая блокировка, которая будет введена, очистит спин-блокировку, потому что даже если экземпляр имеет значение null, !compareAndSet вернет false (как это происходит в первый раз).

После этого любой входящий поток останется вспин-блокировка, потому что instance == null и !compareAndSet равны true. Когда создание экземпляра завершено, спин-блокировка всегда будет проваливаться из-за первого условия.

Это в основном DCL со спин-блокировкой вместо синхронизированной, и нет сценария, в котором я думаю, что приведенный выше код будет полезен.

...