Резьба безопасности в Синглтоне

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

Celery & amp; AMQP позволит вам обрабатывать сломанную задачу, и она снова будет выполнена другим работником (работники Celery будут слушать следующую задачу для работы) до тех пор, пока не будет достигнут атрибут max_retries задачи. Вы можете даже вызывать задачи при сбое, например, протоколировать сбой, или отправлять электронное письмо администратору после достижения max_retries.

И вы можете распространять серверы Celery и AMQP, когда вам нужно масштабировать применение.

13
задан Robert 26 May 2010 в 11:04
поделиться

5 ответов

Джош Блох рекомендует использовать одноэлементный enum тип для реализации синглтонов (см. Effective Java 2nd Edition, Item 3: Enforce the singleton property with a private constructor or an enum type).

Некоторые люди считают это хаком, так как это не позволяет четко передать намерение, но это действительно работает.

Следующий пример взят прямо из книги.

public enum Elvis {
   INSTANCE;

   public void leaveTheBuilding() { ... }
}

Вот его заключительные аргументы:

Этот подход [...] более лаконичен, предоставляет механизм сериализации бесплатно и обеспечивает железную гарантию от множественных инстанцирований даже перед лицом сложных атак на сериализацию или отражение. Хотя этот подход еще не получил широкого распространения, одноэлементный тип enum является лучшим способом реализации синглтона.


О enum гарантии константного синглтона

JLS 8.9. Перечисления

Тип enum не имеет других экземпляров, кроме тех, которые определены его константами enum. Попытка явного инстанцирования типа enum является ошибкой времени компиляции (§15.9.1).

Метод final clone в Enum гарантирует, что константы перечисления никогда не могут быть клонированы, а специальная обработка механизмом сериализации гарантирует, что дублирующие экземпляры никогда не будут созданы в результате десериализации. Отражательное инстанцирование типов enum запрещено. Вместе эти четыре вещи гарантируют, что не существует никаких экземпляров типа enum, кроме тех, которые определены константами enum.


О ленивой инициализации

Следующий фрагмент:

public class LazyElvis {
    enum Elvis {
        THE_ONE;
        Elvis() {
            System.out.println("I'M STILL ALIVE!!!");
        }       
    }
    public static void main(String[] args) {
        System.out.println("La-dee-daaa...");
        System.out.println(Elvis.THE_ONE);
    }
}

Выдает следующий результат:

La-dee-daaa...
I'M STILL ALIVE!!!
THE_ONE

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

25
ответ дан 1 December 2019 в 18:12
поделиться

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

Эта статья в Википедии предлагает другой метод:

public class Something {
    private Something() {
    }

    private static class LazyHolder {
        private static final Something INSTANCE = new Something();
    }

    public static Something getInstance() {
        return LazyHolder.INSTANCE;
    }
}

Из статьи:

Эта реализация является хорошо работающей и параллельной реализацией, действующей во всех версиях Java.
...
Реализация основана на четко определенной фазе инициализации выполнения в виртуальной машине Java (JVM); подробности см. в разделе 12.4 Спецификации языка Java (JLS).

8
ответ дан 1 December 2019 в 18:12
поделиться

Вы можете использовать этот фрагмент кода из wiki

public class Singleton {
   // Private constructor prevents instantiation from other classes
   private Singleton() {}

   /**
    * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
    * or the first access to SingletonHolder.INSTANCE, not before.
    */
   private static class SingletonHolder { 
     private static final Singleton INSTANCE = new Singleton();
   }

   public static Singleton getInstance() {
     return SingletonHolder.INSTANCE;
   }
 }
2
ответ дан 1 December 2019 в 18:12
поделиться

Джош Блох рекомендует 2 решения:

1) хуже:

class Singleton {

   public static Singleton instance = new Singleton();

   ...
}

2) лучше:

public enum Singleton {

   INSTANCE;

   ...
}
2
ответ дан 1 December 2019 в 18:12
поделиться

Я предпочитаю просто выполнить:

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

    private Singleton(){}

    public Singleton instance(){
        return INSTANCE;
    }
 }

Ленивая инициализация возникает редко. Вы всегда должны начинать с активной инициализации и переходить к отложенной инициализации только в случае возникновения проблем. Если вы не измерили и не определили экземпляр Singleton как виновника проблемы с производительностью, просто используйте активную инициализацию. Так проще и производительнее.

Вы наверняка можете использовать enum, но лично меня это не беспокоит, потому что преимущество перед обычным активным инстанцированием - безопасность (против атак отражения), и большую часть времени мой код в любом случае уязвим для таких атак: p

5
ответ дан 1 December 2019 в 18:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: