CodeGym/Java блог/Случаен/Java Singleton клас
John Squirrels
Ниво
San Francisco

Java Singleton клас

Публикувано в групата
здрасти Днес ще се потопим в детайлите на различни дизайнерски модели, като започнем с Java Singleton шаблона. Нека прегледаме: Howво знаем за дизайнерските модели като цяло? Шаблоните за проектиране са най-добрите практики, които можем да приложим за решаване на редица известни проблеми. Моделите на проектиране обикновено не са обвързани с нито един език за програмиране. Гледайте на тях като на набор от препоръки, които да ви помогнат да избегнете грешки и да избегнете преоткриването на колелото.Шаблони за проектиране: Singleton - 1

Какво е сингълтън в Java?

Singleton е един от най-простите шаблони за проектиране на ниво клас. Понякога хората казват, че „този клас е сингълтън“, което означава, че класът имплементира модела на дизайн сингълтон. Понякога е необходимо да напишем клас, където ограничаваме инстанцията до един обект. Например, клас, отговорен за регистриране or свързване към Единичният модел на дизайн описва How можем да постигнем това. Единичният дизайн е модел, който прави две неща:
  1. Той гарантира, че винаги ще има само един екземпляр на класа.

  2. Той осигурява единна точка за глобален достъп до този екземпляр.

Следователно има две характеристики, които са характерни за почти всяка реализация на единичния модел:
  1. Частен строител. Това ограничава възможността за създаване на обекти от класа извън самия клас.

  2. Публичен статичен метод, който връща екземпляра на класа. Този метод се нарича getInstance . Това е точката на глобален достъп до екземпляра на класа.

Варианти за изпълнение

Единичният дизайн модел се прилага по различни начини. Всеки вариант е добър и лош по свой начин. Както винаги, тук няма идеален вариант, но трябва да се стремим към такъв. Първо, нека да решим Howво представлява добро и лошо и Howви показатели влияят на начина, по който оценяваме различните реализации на шаблона за проектиране. Да започнем с доброто. Ето факторите, които правят внедряването по-сочно и привлекателно:
  • Мързелива инициализация: екземплярът не се създава, докато не е необходим.

  • Прост и прозрачен code: този показател, разбира се, е субективен, но е важен.

  • Безопасност на нишката: правилна работа в многонишкова среда.

  • Висока производителност в многонишкова среда: малко or ниHowво блокиране на нишки при споделяне на ресурс.

Сега минусите. Ще изброим фактори, които поставят внедряването в лоша светлина:
  • Без мързелива инициализация: когато класът се зарежда при стартиране на приложението, независимо дали е необходимо or не (парадоксално, в ИТ света е по-добре да си мързелив)

  • Сложен и труден за четене code. Този показател също е субективен. Ако очите ви започнат да кървят, ще приемем, че изпълнението не е най-доброто.

  • Липса на безопасност на резбата. С други думи, "опасност от нишка". Неправилна работа в многонишкова среда.

  • Лоша производителност в многонишкова среда: нишките се блокират взаимно през цялото време or често, когато споделят ресурс.

Код

Сега сме готови да разгледаме различни варианти за внедряване и да посочим плюсовете и минусите:

просто

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

    private Singleton() {
    }

    public static Singleton getInstance() {
        return INSTANCE;
    }
}
Най-простото изпълнение. Професионалисти:
  • Прост и прозрачен code

  • Безопасност на резбата

  • Висока производителност в многонишкова среда

Минуси:
  • Без мързелива инициализация.
В опит да коригираме предишния недостатък, получаваме реализация номер две:

Мързелива инициализация

public class Singleton {
  private static final Singleton INSTANCE;

  private Singleton() {}

  public static Singleton getInstance() {
    if (INSTANCE == null) {
      INSTANCE = new Singleton();
    }
    return INSTANCE;
  }
}
Професионалисти:
  • Мързелива инициализация.

Минуси:
  • Не е безопасно за нишки

Това изпълнение е интересно. Можем да инициализираме лениво, но сме загубor безопасността на нишката. Без притеснения – ние синхронизираме всичко в изпълнение номер три.

Синхронизиран достъп

public class Singleton {
  private static final Singleton INSTANCE;

  private Singleton() {
  }

  public static synchronized Singleton getInstance() {
    if (INSTANCE == null) {
      INSTANCE = new Singleton();
    }
    return INSTANCE;
  }
}
Професионалисти:
  • Мързелива инициализация.

  • Безопасност на резбата

Минуси:
  • Лоша многонишкова производителност

Отлично! В изпълнение номер три ние възстановяваме безопасността на нишката! Разбира се, това е бавно... Сега методът getInstance е синхронизиран, така че може да се изпълнява само от една нишка в даден момент. Вместо да синхронизираме целия метод, всъщност трябва да синхронизираме само частта от него, която инициализира новия екземпляр. Но не можем просто да използваме синхронизиран блок, за да обвием частта, отговорна за създаването на новия екземпляр. Това няма да гарантира безопасността на нишката. Всичко е малко по-сложно. Правилната синхронизация може да се види по-долу:

Двойно проверено заключване

public class Singleton {
    private static final Singleton INSTANCE;

  private Singleton() {
  }

    public static Singleton getInstance() {
        if (INSTANCE == null) {
            synchronized (Singleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}
Професионалисти:
  • Мързелива инициализация.

  • Безопасност на резбата

  • Висока производителност в многонишкова среда

Минуси:
  • Не се поддържа в по-ранни версии на Java под 1.5 (използването на ключова дума volatile е фиксирано от version 1.5)

Имайте предвид, че за да работи правилно тази опция за внедряване, трябва да е изпълнено едно от двете условия. Променливата INSTANCE трябва да бъде окончателна or непостоянна . Последната имплементация, която ще обсъдим днес, е притежателят на клас singleton .

Притежател на класа

public class Singleton {

   private Singleton() {
   }

   private static class SingletonHolder {
       public static final Singleton HOLDER_INSTANCE = new Singleton();
   }

   public static Singleton getInstance() {
       return SingletonHolder.HOLDER_INSTANCE;
   }
}
Професионалисти:
  • Мързелива инициализация.

  • Безопасност на резбата.

  • Висока производителност в многонишкова среда.

Минуси:
  • Правилната работа изисква гаранция, че единичният обект е инициализиран без грешки. В противен случай първото извикване на метода getInstance ще доведе до ExceptionInInitializerError и всички следващи извиквания ще произведат NoClassDefFoundError .

Това изпълнение е почти перфектно. Той е мързелив, безопасен и бърз. Но има нюанс, Howто е обяснено в списъка с недостатъци. Сравнение на различни изпълнения на единичния модел:
Внедряване Мързелива инициализация Безопасност на резбата Многонишкова производителност Кога да се използва?
просто - + Бърз Никога. Или евентуално когато мързеливата инициализация не е важна. Но никога не би било по-добре.
Мързелива инициализация + - Не е приложимо Винаги, когато многопоточността не е необходима
Синхронизиран достъп + + Бавен Никога. Или евентуално когато многонишковата производителност няма meaning. Но никога не би било по-добре.
Двойно проверено заключване + + Бърз В редки случаи, когато трябва да обработвате изключения, когато създавате сингълтън (когато притежателят на клас сингълтон не е приложим)
Притежател на класа + + Бърз Винаги, когато е необходима многонишковост и има гаранция, че единичният обект ще бъде създаден без проблеми.

Плюсове и минуси на единичния модел

Като цяло сингълтън прави точно това, което се очаква от него:
  1. Той гарантира, че винаги ще има само един екземпляр на класа.

  2. Той осигурява единна точка за глобален достъп до този екземпляр.

Този модел обаче има недостатъци:
  1. Единичният клас нарушава принципа на единичната отговорност: в допълнение към преките си задължения, единичният клас също контролира броя на инстанциите.

  2. Зависимостта на обикновен клас от сингълтън не се вижда в публичния договор на класа.

  3. Глобалните променливи са лоши. В крайна сметка сингълтън се превръща в голяма глобална променлива.

  4. Наличието на сингълтон намалява възможността за тестване на приложението като цяло и в частност на класовете, които използват сингълтона.

И това е! :) Разгледахме Java Singleton Class с вас. Сега, до края на живота си, когато разговаряте с вашите приятели програмисти, можете да споменавате не само колко добър е шаблонът, но и няколко думи за това Howво го прави лош. Успех в усвояването на тези нови знания.

Допълнителна литература:

Коментари
  • Популярен
  • Нов
  • Стар
Трябва да сте влезли, за да оставите коментар
Тази страница все още няма коментари