1
public static Singleton getInstance()
{ 
if (instance == null)
    {
    synchronized(Singleton.class) {  //1
    if (instance == null)          //2
    instance = new Singleton();  //3
        }
    }
    return instance; //4
} 

在上面的代码中,假设有 10 个线程正在调用这个方法,它们都超过了第一个 if 条件,然后一个线程进入同步块并创建实例。即使创建了实例,剩余的 9 个线程也应该一个一个来,它们需要通过同步块,只要任何线程创建了 Singleton 实例,所有其他线程都不应该等待。告诉我是否有解决方案?

4

4 回答 4

0

您是说您希望所有其他九个线程都运行而无需一次获得一个锁。

首先,我不得不提一下,等待初始化后获取锁的性能问题很小。其次,单例是邪恶的,有更好的方法来实现它们。

但是,如果您想部分地重新实现锁,那么您可以这样做。这样做可能有一些现成的Future,但我什么都看不到。无论如何,糟糕的实施让我一头雾水:

private static final AtomicReference<Object> ref = new AtomicReference<>();
    // <Object> as we require two distinguished values. :(
    // (I guess could use a mark.)

public static Singleton getInstance() {
    for (;;) { // May want to play with park to avoid spinning.
        Object obj = ref.get();
        if (obj instanceof Singleton) {
           return (Singleton)obj;
        }
        if (ref.weakCompareAndSet(null, Thread.currentThread())) {
            Singleton instance = null; // To reset on fail.
            try {
                instance = new Singleton();
            } finally {
                ref.set(instance);
            }
            return instance;
        }
    }
}

我想我们可以在不变得太复杂的情况下做得更好,再次假设没有例外:

    {
        Object obj = ref.get();
        if (obj instanceof Singleton) {
           return (Singleton)obj;
        }
    }

    if (ref.compareAndSet(null, Thread.currentThread())) {
        Singleton instance = new Singleton();
        ref.set(instance);
        return instance;
    }

    for (;;) {
        Object obj = ref.get();
        if (obj instanceof Singleton) {
           return (Singleton)obj;
        }
    }
于 2013-02-27T07:33:22.577 回答
0

考虑到 Singleton 不是非常复杂的结构化类或者在构造函数的初始化中没有太多要加载的东西,我认为它的好代码和阻塞时间不会那么多。如果所有线程同时到达,它们必须等到任何一个线程创建第一个对象。

于 2013-02-27T06:54:52.343 回答
0

没有条件同步。这意味着每当您使用同步时,它都会一直强制执行。在上面的示例中,当然可以选择在静态块中初始化 Singleton,然后您不需要 getter 的同步块。

于 2013-02-27T06:55:15.733 回答
0

根据您的设计,剩余的线程确实必须一次通过一个线程 - 实际上对于任何这样的锁定策略,您都会得到相同的结果。也就是说,现在锁定的成本微不足道。

请注意,尽管未显示,但该instance变量必须是volatile此惯用语才能起作用。

如果您想要一种模式来满足您的需求(以低成本进行延迟初始化),那么我建议您使用静态初始化方法(如 Brian Goetz 所推荐的):

public class Singleton {
    static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }

    private Singleton() {
    }

    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }

这种方法简洁整洁,并且也是线程安全的,在您的情况下,访问静态getInstance方法(或任何静态方法)的第一个线程将支付初始化成本,但所有后续线程都不会,也不会阻塞。

于 2013-02-27T09:25:05.030 回答