Отвечая на мой собственный вопрос, чтобы в будущем кто-то смог сэкономить время. aks-engine
имеет эту ошибку, которая хорошо известна. Для решения проблемы воспользуйтесь службой aks
из Azure cli
или порталом управления, который в настоящее время поддерживает развертывание кластера в существующей VNET.
Двойная проверка блокировки оказалась неправильной и ошибочной (как минимум в Java). Сделайте поиск или посмотрите на статью Википедии для точной причины.
Прежде всего, это правильность программы. Если ваш код не является поточно-ориентированным (в многопоточной среде), то он сломан. Корректность важнее, чем оптимизация производительности.
Чтобы быть точным, вам нужно синхронизировать весь метод getInstance
public static synchronized Singleton getInstance() {
if (instance==null) ...
}
или статически инициализировать его
private static final Singleton INSTANCE = new Singleton();
Использование отложенной инициализации для базы данных в веб-сканере, вероятно, не стоит. Ленивая инициализация добавляет сложность и постоянный удар по скорости. Один случай, когда это оправдано, - когда есть большая вероятность, что данные никогда не понадобятся. Кроме того, в интерактивном приложении его можно использовать для сокращения времени запуска и создания иллюзии скорости.
Для неинтерактивного приложения, такого как веб-сканер, которому, безусловно, потребуется его база данных для Существуют сразу, ленивая инициализация плохо подходит.
С другой стороны, веб-сканер легко распараллеливается и значительно выиграет от многопоточности. Использовать его как упражнение для освоения библиотеки java.util.concurrent
было бы крайне полезно. В частности, посмотрите на ConcurrentHashMap
и ConcurrentSkipListMap
, , которые позволят нескольким потокам читать и обновлять общую карту.
Когда вы избавляетесь от ленивой инициализации, самый простой шаблон Singleton это что-то вроде этого:
class Singleton {
static final Singleton INSTANCE = new Singleton();
private Singleton() { }
...
}
Ключевое слово final
является ключевым здесь. Даже если вы предоставляете статический
«геттер» для синглтона, а не прямой доступ к полю, создание синглтона финального
помогает обеспечить корректность и позволяет более агрессивную оптимизацию компилятором JIT.
Если бы ваша жизнь зависела от нескольких микросекунд, то я бы посоветовал вам оптимизировать блокировку ресурсов так, чтобы это имело значение.
Но в данном случае ключевое слово здесь - hobby project. !
Это означает, что если вы синхронизировали весь метод getInstance () , с вами все будет в порядке в 99,9% всех случаев. Я НЕ рекомендовал бы делать это каким-либо другим способом.
Позже, если вы докажете посредством профилирования, что синхронизация getInstance () является узким местом вашего проекта, тогда вы можете двигаться дальше и оптимизировать параллелизм , Но я действительно сомневаюсь, что это доставит вам неприятности.
Джич!
Попробуйте Билл Пью решение инициализации по требованию держателя. Решение является наиболее переносимым среди различных компиляторов Java и виртуальных машин. Решение является поточно-ориентированным и не требует специальных языковых конструкций (т. Е. Энергозависимых и / или синхронизированных).
http://en.wikipedia.org/wiki/Singleton_pattern#The_solution_of_Bill_Pugh
Если вы посмотрите в самый конец этой статьи, вы увидите предложение просто использовать статическое поле. Это было бы моим уклоном: вам не нужно ленивое создание экземпляров (поэтому вам не нужно, чтобы 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. Например, я
Check out this article Implementing the Singleton Pattern in 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();
}
}
Почему бы вам не создать структуру данных, которую вы передаете каждому из потоков как внедрение зависимостей. Таким образом, вам не нужен синглтон. Вам все еще нужно сделать поток безопасным.
В статье, на которую вы ссылались, говорится только о том, чтобы сделать создание одноэлементного объекта, предположительно коллекцией в этом случае, поточно-ориентированным. Вам также понадобится потокобезопасная коллекция, чтобы операции сбора также работали как положено. Убедитесь, что основная коллекция в синглтоне синхронизирована, возможно, используя ConcurrentHashMap .
Как насчет:
public static Singleton getInstance() {
if (instance == null) {
synchronize(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
как утверждает Джошуа Блох в своей книге "Эффективная java 2-е издание", я также согласен, что одноэлементный тип enum - лучший способ реализовать singleton.
public enum Singleton {
INSTANCE;
public void doSomething() { ... }
}