6.
OO模式:单件模式——确保一个类只有一个实例,并提供全局访问点
例子:多个巧克力锅炉可能出现的意外
public class ChocolateBoiler { private boolean empty; private boolean boiled; private static ChocolateBoiler uniqueInstance; private ChocolateBoiler() { empty = true; boiled = false; } public static ChocolateBoiler getInstance() { if (uniqueInstance == null) { System.out.println("Creating unique instance of Chocolate Boiler"); uniqueInstance = new ChocolateBoiler(); } System.out.println("Returning instance of Chocolate Boiler"); return uniqueInstance; } public void fill() { if (isEmpty()) { empty = false; boiled = false; // fill the boiler with a milk/chocolate mixture } } public void drain() { if (!isEmpty() && isBoiled()) { // drain the boiled milk and chocolate empty = true; } } public void boil() { if (!isEmpty() && !isBoiled()) { // bring the contents to a boil boiled = true; } } public boolean isEmpty() { return empty; } public boolean isBoiled() { return boiled; } }
注意粗体代码是如何保证巧克力锅炉的单例的
但同时,我们可能会碰到一点问题:
当多线程的时候,线程一确实还没有实例化巧克力锅炉,同时线程二也判断出巧克力锅炉还没被实例化,这时候线程一、二就会各自实例化自己的巧克力锅炉。
这就很尴尬了。。。
改善方法有3个:
①如果getInstance()的性能对应用程序不是很关键,就将其变为同步方法,多线程灾难几乎可以轻易解决;
public class Singleton { private static Singleton uniqueInstance; // other useful instance variables here private Singleton() {} public static synchronized Singleton getInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } // other useful methods here public String getDescription() { return "I'm a thread safe Singleton!"; } }
②使用“急切”创建实例,而不使用延迟实例化的做法
public class Singleton { private static Singleton uniqueInstance=new Singleton(); // other useful instance variables here private Singleton() {} public static synchronized Singleton getInstance() { return uniqueInstance; } }
这个做法是利用JVM来保证在任何线程访问uniqueInstance静态变量之前,一定先创建此实例。
③用“双重检查加锁”,在getInstance()中减少使用同步(只能用在Java 5及更高版本上)
// // Danger! This implementation of Singleton not // guaranteed to work prior to Java 5 // public class Singleton { private volatile static Singleton uniqueInstance; private Singleton() {} public static Singleton getInstance() { if (uniqueInstance == null) { synchronized (Singleton.class) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; } }