所以我正在考虑建立一个业余爱好项目,这是一种临时性的事情,只是为了温习我的编程/设计。

它基本上是一个多线程网络蜘蛛,更新相同的数据结构object->int。

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

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

有帮助吗?

解决方案

双检锁已被证明是不正确的,有缺陷的(如至少在Java中)。做搜索还是看维基百科的确切原因进入

首先是程序的正确性。如果你的代码是不是线程安全的(在多线程环境下),则是坏了。正确性至上性能优化之前。

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

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

或静态初始化

private static final Singleton INSTANCE = new Singleton();

其他提示

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

对于像网络爬虫这样的非交互式应用程序来说,它肯定需要其数据库立即存在,延迟初始化不太合适。

另一方面,网络爬虫很容易并行化,并且将从多线程中受益匪浅。使用它作为练习来掌握 java.util.concurrent 图书馆将非常值得。具体看 ConcurrentHashMapConcurrentSkipListMap, 这将允许多个线程读取和更新共享映射。

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

class Singleton {

  static final Singleton INSTANCE = new Singleton();

  private Singleton() { }

  ...

}

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

如果您的生命取决于几微秒,那么我建议您将资源锁定优化到真正重要的地方。

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

这意味着如果您同步整个 获取实例() 方法 99.9% 的情况下你都会没事的。我不建议以任何其他方式这样做。

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

杰奇!

尝试一下 比尔·皮尤 按需初始化的解决方案。该解决方案在不同的 Java 编译器和虚拟机上是最可移植的。该解决方案是线程安全的,不需要特殊的语言结构(即易失性和/或同步)。

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

约书亚布洛赫认为在他的著作“有效的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;
  }
}

请注意,单例现在是在安装静态字段期间构建的。这应该可行,并且不会面临潜在的错误同步的线程风险。

综上所述,也许您真正需要的是现代 JDK 中可用的线程安全数据结构之一。例如,我是 并发哈希映射:线程安全加上我不必编写代码(FTW!)。

为什么不创建传递给每个线程依赖注入的数据结构。这样,你并不需要一个单身。你仍然需要进行线程安全的。

您只引用有关使在这种情况下,创建单一对象,想必集合会谈的文章,线程安全的。您还需要一个线程安全的集合,以便收集操作预期也行。确保在单身底层集合是同步的,多半是使用的ConcurrentHashMap

看看这篇文章实现C#中的单例模式

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;
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top