单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
Singleton结构图
Singleton类:
public class Singleton {
private static Singleton instance;
/**
* 构造方法让其private,这就堵死了外界利用
* new创建此类实例的可能
* @author Guo
*/
private Singleton() {
}
/**
* 此方法是获得本类实例的
* 唯一全局访问点
* @author Guo
*/
public static Singleton getInstance() {
if(instance == null)
instance = new Singleton();
return instance;
}
}
客户端:
public class Client {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
if(s1 == s2)
System.out.println("两个对象是相同的实例");
else
System.out.println("两个对象时不同的实例");
}
}
其实你会发现这个Singleton的线程是不安全的,现在我们演示一个线程安全的Singleton:
public class Singleton {
private static Singleton instance;
/**
* 程序运行的时候创建一个静态只读的进程辅助对象
* @author Guo
*/
private static Object object = new Object();
private Singleton() {
}
public static Singleton getInstance() {
/**
* 在同一个时刻加了锁的那部分程序只有一个线程可以进去
* @author Guo
*/
synchronized (object) {
if(instance == null)
instance = new Singleton();
return instance;
}
}
}
当然还有一种Singleton的方式也是线程安全的,但是就没有延迟加载,在类初始化的时候就实例化好了:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
如何创建并发访问效率高的单例 : Double-Check Locking
若这个类的实例已经是非空的话,你用线程锁去锁住这个线程就显得不必要了,所以我们可以这么做:
public static Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null)
instance = new Singleton();
}
}
return instance;
}
要使线程安全并且可以延迟加载的Singleton实现方法还有一种:Initialization on demand holder
public class LazySingleton {
private static class SingletonHolder {
private static final LazySingleton instance = new LazySingleton();
}
public static LazySingleton getInstance() {
return SingletonHolder.instance;
}
}
该类没有static属性,所以在类初始化的时候没有加载任何东西,但是一旦调用了getInstance方法后,JVM加载SingletonHolder类,加载static属性instance,生成唯一一份实例,这样保证了线程的安全,而且具有延迟性。