2011-07-07 57 views
0

任何人都可以解释下面的代码如何在多线程环境中正常工作,特别是当它不使用synchronized关键字时?单线程在多线程中不使用同步关键字

public class Singleton { 
private Singleton() {} 

private static class SingletonHolder { 
    private static final Singleton INSTANCE = new Singleton(); 
} 

public static Singleton getInstance() { 
    return SingletonHolder.INSTANCE; 
} 
} 
+0

@leppie,这似乎有点苛刻...,尤其是对于相对新手(虽然我不否认你正确的做到这一点,我们的票是我们自己做的,因为我们认为合适的 - “我不同意你说的话,但我会为你的死亡权利而斗争”以及所有爵士乐)。我认为这些选票适用于Q/A本身,而不是发布人员的某种奖励/惩罚机制。由于您实际上是通过添加标签来修复问题的,因此不能认为问题不足。 IMOBIBWBJAMW(在我看来,但我以前错了 - 只是问我的妻子):-) – paxdiablo

回答

1

为异步单身人士可以工作得很好,在线程环境提供他们在一个线程中实例化之前其他线程试图使用它们。

这可能就像在启动任何其他线程之前从主线程调用getInstance()一样简单。

但是,这在这种特殊情况下无关紧要。由于您的实例变量是static final,这意味着它将在最初加载类时构建。通过调用getInstance(),类加载器引入该类,并在作为其一部分构建INSTANCE成员之前,允许通过getInstance()进行调用。

类加载器本身具有锁定机制以防止多线程并发执行,因此所有对getInstance()(包括第一个,紧随该类加载之后)的调用都将返回已经初始化的值。

+0

当多个线程试图调用Signleton.getInstance()时,上面的代码提供了唯一的实例,而不是彼此共享该实例。现在,我想知道当没有同步关键字时它会发生什么?因为即使多个线程可以同时调用SingletonHolder,那么在这里怎么会没有任何同步问题呢? – Mike

+0

@Mike,他们不提供独特的实例。有一个_one_实例很早就构建完成,每次调用getInstance都会返回该实例。 – paxdiablo

+0

那么,这是否意味着当2个线程同时调用getInstance时,它会创建它们的不同实例? – Mike

0

至于前期初始化,不需要使用同步关键字,因为您静态地初始化您的实例,几乎在每种情况下都是因为两个原因而首选的方法。您可以在应用程序的运行时间内分摊昂贵的初始化成本,其中两个(对您来说尤其重要)是它不需要同步,因此您可以避免多毛的双重检查锁定方案。

如果您选择使用延迟初始化,那么您需要确保整个初始化过程是同步的,否则在多处理器环境中您会冒着创建两个单例实例的风险。 Double Checked Locking And Why its a problem

初始化后,您的代码将在多线程环境中正常工作。需要注意的是,您在所有线程中共享一个实例,因此您需要确保您的INSTANCE是线程安全的。有两种方法可以做到这一点。首先,您可以确保您的所有成员都是私有的,并且可以访问更改INSTANCE's状态的方法,使用​​或包含发生状态修改的同步块。

实现线程安全性的第二种也许更好的方法是预先初始化您的实例,并在其初始化后使其不可变。不可变对象可以在线程间自由共享,而无需同步。阅读Java实践文章以获取有关不可变对象以及如何创建它们的更多信息。

Java Practices: Immutable objects