正确使用同步单身?

因此,我正在考虑建立一个业余爱好项目,一种类似的东西,只是为了了解我的编程/设计。

它基本上是一个multithreading的Web蜘蛛,更新相同的数据结构对象 – > int。

因此,为此使用数据库绝对有点过分了,我唯一能想到的是用于包含我的数据结构的线程安全单例。 http://web.archive.org/web/20121106190537/http://www.ibm.com/developerworks/java/library/j-dcl/index.html

我应该考虑采用不同的方法吗?

双重检查锁定已被certificate是不正确和有缺陷的(至少在Java中)。 出于确切原因,请搜索或查看维基百科的条目 。

首先是程序的正确性。 如果您的代码不是线程安全的(在multithreading环境中),那么它就会被破坏。 在性能优化之前,首先是正确性。

要正确,您必须同步整个getInstance方法

 public static synchronized Singleton getInstance() { if (instance==null) ... } 

或静态初始化它

 private static final Singleton INSTANCE = new Singleton(); 

在Web爬网程序中对数据库使用延迟初始化可能不值得。 延迟初始化增加了复杂性和持续的速度命中。 一个合理的案例是,很有可能永远不需要数据。 此外,在交互式应用程序中,它可用于减少启动时间并提供速度幻觉

对于像web-crawler这样的非交互式应用程序,它肯定需要立即存在其数据库,懒惰初始化是一个不合适的。

另一方面,Web爬虫很容易并行化,并且可以从multithreading中受益匪浅。 使用它作为练习来掌握java.util.concurrent库是非常值得的。 具体来说,查看ConcurrentHashMapConcurrentSkipListMap ,它将允许多个线程读取和更新共享映射。

当您摆脱延迟初始化时,最简单的Singleton模式是这样的:

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

关键字final是这里的关键。 即使您为单例提供static “getter”而不是允许直接字段访问,使单例final有助于确保正确性并允许JIT编译器进行更积极的优化。

如果你的生活依赖于几微秒,那么我会建议你优化你的资源锁定到实际重要的地方。

但在这种情况下,这里的关键字是业余爱好项目

这意味着,如果你同步了整个getInstance()方法,那么99.9%的情况都可以。 我不建议任何其他方式。

稍后,如果您通过分析certificategetInstance()同步是项目的瓶颈,那么您可以继续并优化并发性。 但我真的怀疑它会给你带来麻烦。

Jeach!

尝试Bill Pugh解决方案的初始化按需持有者习惯用法。 该解决方案在不同的Java编译器和虚拟机中最易于移植。 该解决方案是线程安全的,无需特殊的语言结构(即易失性和/或同步)。

http://en.wikipedia.org/wiki/Singleton_pattern#The_solution_of_Bill_Pugh

正如Joshua Bloch在他的书“有效的Java第二版”中所论证的那样,我也同意单个元素枚举类型是实现单例的最佳方式。

 public enum Singleton { INSTANCE; public void doSomething() { ... } } 

如果您查看该文章的最底部,您将看到仅使用静态字段的建议。 这将是我的倾向:你并不真正需要延迟实例化(因此你不需要getInstance()同时成为访问者和工厂方法)。 你只想确保你只有一个这样的东西。 如果你真的需要全局访问这样的东西,我会在最底层使用该代码示例 :

 class Singleton { private Vector v; private boolean inUse; private static Singleton instance = new Singleton(); private Singleton() { v = new Vector(); inUse = true; //... } public static Singleton getInstance() { return instance; } } 

请注意,现在在安装静态字段期间构建了Singleton。 这应该工作,而不是面临潜在的错误同步事物的线程风险。

总而言之,您真正需要的可能是现代JDK中可用的线程安全数据结构之一。 例如,我是ConcurrentHashMap的忠实粉丝:线程安全加上我不必编写代码(FTW!)。

为什么不创建作为dependency injection传递给每个线程的数据结构。 这样你就不需要单身人士了。 你仍然需要使线程安全。

您引用的文章仅讨论如何创建单例对象,在这种情况下可能是线程安全的集合。 您还需要一个线程安全的集合,以便集合操作也可以按预期工作。 确保单例中的基础集合是同步的,可能使用ConcurrentHashMap 。

看看这篇文章在C#中实现Singleton模式

 public sealed class Singleton { Singleton() { } public static Singleton Instance { get { return Nested.instance; } } class Nested { // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit static Nested() { } internal static readonly Singleton instance = new Singleton(); } } 

怎么样:

 public static Singleton getInstance() { if (instance == null) { synchronize(Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }