Правильное использование синхронизированного синглтона?

Итак, я думаю о том, чтобы построить проект для хобби, один из видов, просто чтобы освежить мое программирование/дизайн.

В основном это многопоточный веб-паук, обновляющий ту же структуру данных object- > int.

Таким образом, для этого, безусловно, излишне использовать базу данных, и единственное, что я могу придумать, это поточно-безопасный синглтон, используемый для хранения моей структуры данных. http://web.archive.org/web/20121106190537/http://www.ibm.com/developerworks/java/library/j-dcl/index.html

Есть ли другой подход, на который я должен обратить внимание?

Ответ 1

Проверено, что блокировка с двойным проверкой была неправильной и ошибочной (как минимум на Java). Сделайте поиск или посмотрите запись в Википедии по той же причине.

Прежде всего, это правильность программы. Если ваш код не является потокобезопасным (в многопоточной среде), то он сломан. Прежде чем оптимизировать работу, сначала необходимо выполнить правильность.

Чтобы быть правильным, вам нужно будет синхронизировать весь метод getInstance

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

или статически инициализировать его

private static final Singleton INSTANCE = new Singleton();

Ответ 2

Использование ленивой инициализации для базы данных в веб-искателе, вероятно, не стоит. Ленивая инициализация добавляет сложности и постоянный удар скорости. Один случай, когда это оправдано, - это когда есть вероятность, что данные никогда не понадобятся. Кроме того, в интерактивном приложении его можно использовать для уменьшения времени запуска и создания иллюзии скорости.

Для неинтерактивного приложения, такого как веб-искатель, который, несомненно, понадобится, чтобы его база данных существовала сразу, ленивая инициализация плохо подходит.

С другой стороны, веб-гусеничный манипулятор легко распараллеливается и в значительной степени выиграет от многопоточной обработки. Использование его в качестве упражнения для освоения библиотеки java.util.concurrent было бы чрезвычайно полезным. В частности, посмотрите ConcurrentHashMap и ConcurrentSkipListMap, который позволит нескольким потокам читать и обновлять общую карту.

Когда вы избавитесь от ленивой инициализации, простейший шаблон Singleton выглядит примерно так:

class Singleton {

  static final Singleton INSTANCE = new Singleton();

  private Singleton() { }

  ...

}

Ключевое слово final - это ключ. Даже если вы предоставляете static "getter" для синглтона, а не разрешаете прямой доступ к полям, создание singleton final помогает обеспечить правильность и позволяет более агрессивную оптимизацию компилятором JIT.

Ответ 3

Если бы ваша жизнь зависела от нескольких микросекунд, я бы посоветовал вам оптимизировать блокировку ресурсов там, где это действительно имело значение.

Но в данном случае ключевое слово здесь hobby project!

Это означает, что если вы синхронизировали весь метод getInstance(), вы будете в порядке в 99,9% всех случаев. Я бы не рекомендовал делать это по-другому.

Позже, если вы докажете с помощью профилирования, что синхронизация getInstance() является узким местом вашего проекта, вы можете перейти и оптимизировать concurrency. Но я действительно сомневаюсь, что это вызовет у вас проблемы.

Jeach!

Ответ 4

Попробуйте решение инициализации Bill Pugh для идиомы спроса. Решение является наиболее переносимым для разных компиляторов Java и виртуальных машин. Решение является потокобезопасным, не требуя специальных языковых конструкций (т.е. Изменчивых и/или синхронизированных).

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

Ответ 5

как утверждает Джошуа Блох в своей книге "Эффективное Java-издание 2", я также согласен с тем, что один тип перечисления элементов - лучший способ реализовать синглтон.

public enum Singleton {
  INSTANCE;

  public void doSomething() { ... }
}

Ответ 6

Если вы посмотрите на самую нижнюю часть этой статьи, вы увидите предложение просто использовать статическое поле. Это была бы моя склонность: вам не нужна ленивая инстанция (поэтому вам не нужно getInstance() быть как аксессуром, так и методом factory). Вы просто хотите убедиться, что у вас есть одна и только одна из этих вещей. Если вам действительно нужен глобальный доступ к одной из таких вещей, я бы использовал этот пример кода в самом низу:

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!).

Ответ 7

Как насчет:

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

  return instance;
}

Ответ 8

Почему бы вам не создать структуру данных, которую вы передаете каждому из потоков в качестве инъекции зависимостей. Таким образом, вам не нужен синглтон. Вам все равно нужно сделать поток безопасным.

Ответ 9

В статье, на которую вы ссылались, говорится только о создании объекта singleton, предположительно коллекции в этом случае, потокобезопасной. Вам также нужна потокобезопасная коллекция, чтобы операции сбора также работали, как ожидалось. Убедитесь, что базовая коллекция в singleton синхронизирована, возможно, используя ConcurrentHashMap.

Ответ 10

Ознакомьтесь с этой статьей Внедрение шаблона 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();
    }
}