简体   繁体   English

这个Singleton是一个线程安全的吗?

[英]Is this Singleton a thread-safe one?

Basing on this topic , I put down an interesting version of Singleton pattern which implementation is based on AtomicIntegers. 基于这个主题 ,我提出了一个有趣的Singleton模式版本,该实现基于AtomicIntegers。

The questions are: 问题是:

  • is this implementation correct and thread-safe, and generally is it possible to use Atomic Variables for thread synchronization and management? 这个实现是正确的和线程安全的,通常可以使用Atomic Variables进行线程同步和管理吗?
  • Additional question: if this implementation is thread-safe, do I really need a volatile modifier for instance variable? 附加问题:如果这个实现是线程安全的,我真的需要一个volatile修饰符作为实例变量吗?
public class StrangeSingleton
{

    private StrangeSingleton() {};

    private static volatile Object instance;

    private static AtomicInteger initCounter = new AtomicInteger();
    private static AtomicInteger readyCounter = new AtomicInteger();

    static Object getInstance()
    {

        if (initCounter.incrementAndGet() == 1)
        {
            instance = new Object();

            readyCounter.incrementAndGet();

            return instance;
        }
        else if (readyCounter.get() == 1)
        {
            return instance;
        }
        else
        {
            //initialization not complete yet.
            //write here some logic you want:               
            //sleep for 5s and try one more time,
            //or throw Exception, or return null..

            return null;
        }
    }
}

UPDATE: added the private constructor, but its not the point. 更新:添加了私有构造函数,但它不是重点。

is this implementation is correct and thread-safe, and generally is it possible to use Atomic Variables for thread synchronization and management? 这个实现是正确的和线程安全的,通常可以使用Atomic Variables进行线程同步和管理吗?

Its is but it usually more complicated and cpu intensive as you need to busy wait to respond to changes quickly. 但它通常更加复杂和CPU密集,因为您需要忙着等待快速响应变化。

Additional question: if this implementation is thread-safe, do I really need a volatile modifier for instance variable? 附加问题:如果这个实现是线程安全的,我真的需要一个volatile修饰符作为实例变量吗?

In this case you don't because AtomicInteger contain volatile fields which will ensure correct happens-before/happens-after behaviour. 在这种情况下,您不会这样做,因为AtomicInteger包含易失性字段,这将确保正确发生之前/发生后行为。


Of course you could just use an enum which is thread safe and much simpler ;) 当然你可以使用一个线程安全且更简单的枚举;)

enum Singleton {
    INSTANCE;
}

is this implementation correct and thread-safe, and generally is it possible to use Atomic Variables for thread synchronization and management? 这个实现是正确的和线程安全的,通常可以使用Atomic Variables进行线程同步和管理吗?

Yes, but for the readyCounter variable you should probably use a CountDownLatch , like this: 是的,但对于readyCounter变量,您应该使用CountDownLatch ,如下所示:

private static AtomicInteger initCounter = new AtomicInteger();
private static CountDownLatch readyCounter = new CountDownLatch(1);

static Object getInstance()
{

    if (initCounter.incrementAndGet() == 1)
    {
        try {
            instance = new Object();
            return instance;
        } finally {
            readyCounter.countDown();
        }
    }
    else
    {
        readyCounter.await();
        return instance;
    }
}

Calling await() also solves the initialization race condition. 调用await()也可以解决初始化竞争条件。 (I also added a try-finally block to avoid deadlocks on a constructor exception.) (我还添加了一个try-finally块来避免构造函数异常死锁。)

Additional question: if this implementation is thread-safe, do I really need a volatile modifier for instance variable? 附加问题:如果这个实现是线程安全的,我真的需要一个volatile修饰符作为实例变量吗?

No, not if you call the relevant AtomicInteger or CountDownLatch functions before accessing the instance variable. 不,如果在访问实例变量之前调用相关的AtomicIntegerCountDownLatch函数,则不会。 Look for happens-before in the documentation . 文档中寻找发生的事情

Thread T1 may be suspended on instance = new Object(); 线程T1可以挂在instance = new Object(); , T2 will then hit the else{} block since readyCounter hasn't been incremented yet. T2将会触及else{}块,因为readyCounter尚未增加。 Thtat is not quite correct since initialization has completed, what's lagging behind is the state book-keeping 由于初始化已经完成,Thtat不太正确,落后的是状态簿记

I would rather do one synchronized block in your getInstance() method. 我宁愿在你的getInstance()方法中做一个synchronized块。 This is sufficient. 这就足够了。 You don't need these strange counters which are also not so safe as @David noticed. 你不需要这些奇怪的计数器,这些计数器也不像@David注意到的那么安全。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM