使用原子非阻塞方法的单项与同步化

问题描述 投票:0回答:1

我试图利用非阻塞原子布尔API生成单例对象而不是同步对象。

我有2个实现

  1. 通过双重锁定和同步关键字
  2. 通过无阻塞原子通话

我相信通过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正确识别出上述暗示不是线程安全的。我固定在下一个。

// 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;

}
java multithreading singleton atomic nonblocking
1个回答
1
投票

第二个实现不是线程安全的。一种简单的显示方法是将Thread.sleep(10);(或更多)放入Singleton的构造函数中。

[这导致第一个线程将isInitialized设置为trueinstance仍然为空时,然后调用new Singleton();

[另一个线程将instance视为null,它不会进入if块,因为布尔值现在是true,然后它将返回instance,该值为空。

所以竞争条件以NullPointerException结尾。

如果要强制将此解决方案变为可行的解决方案,则必须使用自旋锁,并且可能会发生类似这样的事情(这是早晨代码,所以请让我知道是否有奇怪的事情:]]]

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!compareAndSettrue。实例构造完成后,由于第一个条件,自旋锁将始终掉线。

这基本上是具有自旋锁的DCL,而不是同步的,而且我认为上面的代码在任何情况下都不会有用。

© www.soinside.com 2019 - 2024. All rights reserved.