HeadFirst设计模式之单例模式

一、

1.The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.

2.

3.

二、例子一:线程不安全

 1 package headfirst.designpatterns.singleton.chocolate;
 2  
 3 public class ChocolateBoiler {
 4     private boolean empty;
 5     private boolean boiled;
 6     private static ChocolateBoiler uniqueInstance;
 7   
 8     private ChocolateBoiler() {
 9         empty = true;
10         boiled = false;
11     }
12   
13     public static ChocolateBoiler getInstance() {
14         if (uniqueInstance == null) {
15             System.out.println("Creating unique instance of Chocolate Boiler");
16             uniqueInstance = new ChocolateBoiler();
17         }
18         System.out.println("Returning instance of Chocolate Boiler");
19         return uniqueInstance;
20     }
21 
22     public void fill() {
23         if (isEmpty()) {
24             empty = false;
25             boiled = false;
26             // fill the boiler with a milk/chocolate mixture
27         }
28     }
29  
30     public void drain() {
31         if (!isEmpty() && isBoiled()) {
32             // drain the boiled milk and chocolate
33             empty = true;
34         }
35     }
36  
37     public void boil() {
38         if (!isEmpty() && !isBoiled()) {
39             // bring the contents to a boil
40             boiled = true;
41         }
42     }
43   
44     public boolean isEmpty() {
45         return empty;
46     }
47  
48     public boolean isBoiled() {
49         return boiled;
50     }
51 }

三、加上synchronized

直接在getInstance()方法中加上synchronized虽然线程安全,但得不尝失。因为理想的情况是只在第一次访问getInstance时才需要同步,以后的访问不用同步,因为已经有了instance了

 1 package headfirst.designpatterns.singleton.threadsafe;
 2 
 3 public class Singleton {
 4     private static Singleton uniqueInstance;
 5  
 6     // other useful instance variables here
 7  
 8     private Singleton() {}
 9  
10     public static synchronized Singleton getInstance() {
11         if (uniqueInstance == null) {
12             uniqueInstance = new Singleton();
13         }
14         return uniqueInstance;
15     }
16  
17     // other useful methods here
18     public String getDescription() {
19         return "I'm a thread safe Singleton!";
20     }
21 }

四、用饿汉式解决线程安全(用static ,JVM会在任何线程访问前初始化变量)

 1 package headfirst.designpatterns.singleton.stat;
 2 
 3 public class Singleton {
 4     private static Singleton uniqueInstance = new Singleton();
 5  
 6     private Singleton() {}
 7  
 8     public static Singleton getInstance() {
 9         return uniqueInstance;
10     }
11     
12     // other useful methods here
13     public String getDescription() {
14         return "I'm a statically initialized Singleton!";
15     }
16 }

Using this approach, we rely on the JVM to create the unique instance of the Singleton when the class is loaded. The JVM guarantees that the instance will be created before any thread accesses the static uniqueInstance variable.

五、用双重检查

 1 package headfirst.designpatterns.singleton.dcl;
 2 
 3 //
 4 // Danger!  This implementation of Singleton not
 5 // guaranteed to work prior to Java 5
 6 //
 7 
 8 public class Singleton {
 9     private volatile static Singleton uniqueInstance;
10  
11     private Singleton() {}
12  
13     public static Singleton getInstance() {
14         if (uniqueInstance == null) {
15             synchronized (Singleton.class) {
16                 if (uniqueInstance == null) {
17                     uniqueInstance = new Singleton();
18                 }
19             }
20         }
21         return uniqueInstance;
22     }
23 }

With double-checked locking, we first check to see if an instance is created, and if not, THEN we synchronize. This way, we only synchronize the first time through, just what we want.

The volatile keyword ensures that multiple threads handle the uniqueInstance variable correctly when it is being initialized to the Singleton instance.

六、

1.

Q: What about class loaders?
I heard there is a chance that two class loaders could each end up with their own instance of Singleton.A: Yes, that is true as each class loader defines a namespace. If you have two or more classloaders, you can load the same class multiple times (once in each classloader). Now, if that class happens to be a Singleton, then since we have more than one version of the class, we also have more than one instance of the Singleton. So, if you are using multiple classloaders
and Singletons, be careful. One way around this problem is to specify the classloader yourself.

2.

I still don’t totally understand why global variables are worse than a Singleton.
A: In Java, global variables are basically static references to objects.There are a couple of disadvantages to using global variables in this manner. We’ve already mentioned one: the issue of lazy versus eager instantiation. But we need to keep in mind the intent of the pattern: to ensure only one instance of a class exists and to provide global access. A
global variable can provide the latter,but not the former. Global variables also tend to encourage developers
to pollute the namespace with lots of global references to small objects.Singletons don’t encourage this in the same way, but can be abused nonetheless.

 

原文地址:https://www.cnblogs.com/shamgod/p/5259422.html