Head First 设计模式学习笔记 —— 单件模式
—— 只生一个孩儿
问题来源:
如何确保一个类只有一个实例?
单件模式让类来管理自己的一个实例,避免程序自行产生其他该类的实例。当需要该类的实例时,程序询问该类是否有实例,如果该类有实例,则返回该实例;如果该类无实例,则构造一个实例并返回,并在全局中维护这唯一的一个实例。总结来讲,单件模式就是只生一个“孩儿”。下面是经典单件模式的类图:
Singleton.java代码如下:
public class Singleton {
private static Singleton instance;
public String name = "singleton";
private Singleton() {}
private Singleton(String name) {
this.name = name;
}
public static Singleton getInstance(String name) {
if(instance == null) {
instance = new Singleton(name);
}
return instance;
}
public void printName() {
System.out.println("My name is : " + name);
}
}
Singleton类为了避免被公开实例化,因此将构造方法设为“私有的”,通过静态方法getInstance()判断Singleton类是否存在实例,如果存在实例,则直接返回,否则调用构造方法构造一个实例并返回。
测试程序 test.java 代码如下:
import java.lang.reflect.Field;
public class test {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance("singleton1");
singleton1.printName();
Singleton singleton2 = Singleton.getInstance("singleton2");
singleton2.printName(); //singleton2 and singleton1 is the same object
System.out.println(singleton1);
System.out.println(singleton2);
}
}
test.java代码中,尽管调用了多次getInstance()方法,但是通过结果可以发现,程序中仅有一个Singleton实例。结果图如下:
经典单件模式在多线程中就不适用了,因为对于经典单件模式,JVM并不能保证多个线程互斥地访问实例,因此多个线程可能会产生多个实例。解决的方法是同步各个线程,当一个线程访问实例时,保持对该实例的锁定,其他试图访问该实例的线程将被阻塞。
按上述思路修改后的代码如下,Singleton.java:
public class Singleton {
private volatile static Singleton instance;
public String name = "singleton";
private Singleton() {}
private Singleton(String name) {
this.name = name;
}
public static Singleton getInstance(String name) {
if(instance == null) {
synchronize (Singleton.class) { //对Singleton类进行同步
if(instance == null) {
instance = new Singleton(name);
}
}
}
return instance;
}
public void printName() {
System.out.println("My name is : " + name);
}
}
上述代码中,使用volatile关键字修饰instance变量,保证其他线程在使用该变量时,都会读取变量最后一次修改后最新的值。synchronized关键字同步Singleton类,保证全局多个线程间对只有一个线程可以执行同步块内的代码。
参考自: