In diesem Artikel wird weiterhin das Singleton-Muster in der Reihe von 23 Designmustern vorgestellt.
Konzept:
Das Singleton-Muster ist ein gängiges Designmuster in Java. Es gibt drei Haupttypen, um das Singleton-Muster zu schreiben: „Lazy Singleton“ und „Hunger Man“. Singleton.
Der Singleton-Modus hat die folgenden Eigenschaften:
1. Eine Singleton-Klasse kann nur eine Instanz haben.
2. Die Singleton-Klasse muss ihre eigene eindeutige Instanz erstellen.
3. Die Singleton-Klasse muss diese Instanz allen anderen Objekten bereitstellen.
Das Singleton-Muster stellt sicher, dass eine Klasse nur eine Instanz hat, sich selbst instanziiert und diese Instanz dem gesamten System zur Verfügung stellt. In Computersystemen werden Thread-Pools, Caches, Protokollobjekte, Dialogfelder, Drucker und Grafikkartentreiberobjekte häufig als Singletons konzipiert. Diese Anwendungen verfügen alle mehr oder weniger über die Funktionalität von Ressourcenmanagern. Jeder Computer kann über mehrere Drucker verfügen, es kann jedoch nur ein Druckerspooler vorhanden sein, um zu verhindern, dass zwei Druckaufträge gleichzeitig auf dem Drucker ausgegeben werden. Jeder Computer kann über mehrere Kommunikationsanschlüsse verfügen. Das System sollte diese Kommunikationsanschlüsse zentral verwalten, um zu verhindern, dass ein Kommunikationsanschluss gleichzeitig von zwei Anforderungen aufgerufen wird. Kurz gesagt besteht der Zweck der Wahl des Singleton-Modus darin, inkonsistente Zustände und langfristige Richtlinien zu vermeiden.
1. Lazy Singleton
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Singleton verhindert, dass die Klasse extern instanziiert wird, indem die Konstruktionsmethode auf privat beschränkt wird Auf die Instanz von kann nur über die Methode getInstance() zugegriffen werden.
(Tatsächlich ist es durch den Java-Reflexionsmechanismus möglich, eine Klasse mit einem privaten Konstruktor zu instanziieren, wodurch grundsätzlich alle Java-Singleton-Implementierungen ungültig werden. Dieses Problem wird hier nicht besprochen, also verstecken wir es für Es wird davon ausgegangen, dass der Reflexionsmechanismus nicht vorhanden ist. Die obige Implementierung von Lazy Singleton berücksichtigt jedoch keine Thread-Sicherheit Um eine Thread-Sicherheit zu erreichen, gibt es die folgenden drei Methoden, die alle die getInstance-Methode ändern, um die Thread-Sicherheit von Singletons im Lazy-Stil sicherzustellen Wenn Sie viel über Thread-Sicherheit wissen, können Sie zunächst die folgenden drei Schritte überspringen, einen Blick auf den Singleton im Hungry-Stil werfen und dann nach dem Lesen noch einmal über Thread-Sicherheitsprobleme nachdenken:
1. Synchronisierung zur getInstance-Methode hinzufügen
1 2 3 4 5 6 |
|
1 2 3 4 5 6 7 8 9 10 |
|
1 2 3 4 5 6 7 8 9 |
|
2. Hungriger Singleton im chinesischen Stil
Hungriger chinesischer Stil in When Eine Klasse wird erstellt, ein statisches Objekt wird für die Systemverwendung erstellt und wird in Zukunft nicht mehr geändert, sodass es von Natur aus Thread-sicher ist.
1 2 3 4 5 6 7 8 9 |
|
3. Registrierter Singleton (kann ignoriert werden)
Registrierter Singleton wird tatsächlich verwaltet. Erstellen Sie einen Satz von Instanzen der Singleton-Klasse und speichern Sie diese Instanzen in einer Map (Registrierungsbuch). Für Instanzen, die registriert wurden, werden sie direkt von der Map zurückgegeben. Für diejenigen, die nicht registriert wurden, werden sie zuerst registriert und dann zurückgegeben.
Hier habe ich den Singleton im Registrierungsstil als vernachlässigbar markiert. Nach meinem Verständnis wird er aufgrund des statischen Methodenblocks immer noch weniger verwendet Darin wird sein Singleton instanziiert, wenn die Klasse geladen wird.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
Der Unterschied zwischen hungrigem Mann und faulem Mann
Vom Namen her hungriger Mann und fauler Mann,
1. Thread-Sicherheit:
Hungriger chinesischer Stil ist geboren Es ist threadsicher und kann problemlos direkt für Multithreading verwendet werden
Der hungrige chinesische Stil instanziiert ein statisches Objekt, wenn die Klasse erstellt wird, unabhängig davon, was später passiert. Wenn Sie diesen Singleton nicht verwenden, belegt er eine gewisse Menge an Speicher, aber die Geschwindigkeit ist entsprechend höher, wenn Sie ihn zum ersten Mal aufrufen, da seine Ressourcen initialisiert wurden,
什么是线程安全?
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作,或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题,那就是线程安全的。
应用
以下是一个单例类使用的例子,以懒汉式为例,这里为了保证线程安全,使用了双重检查锁定的方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
可以看到里面加了volatile关键字来声明单例对象,既然synchronized已经起到了多线程下原子性、有序性、可见性的作用,为什么还要加volatile呢,原因已经在下面评论中提到,
还有疑问可参考http://www.iteye.com/topic/652440
和http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
运行结果:
结论:由结果可以得知单例模式为一个面向对象的应用程序提供了对象惟一的访问点,不管它实现何种功能,整个应用程序都会同享一个实例对象。
对于单例模式的几种实现方式,知道饿汉式和懒汉式的区别,线程安全,资源加载的时机,还有懒汉式为了实现线程安全的3种方式的细微差别。