单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个好的方法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。------《设计模式:可复用面向对象软件的基础》
例如,读取配置文件信息的类,这个类只需要在应用启动的时候读取一次就行,以后就从这个类获取相关配置信息就行。
一个类只有一个实例,每次使用时,都返回唯一的实例。相对于那些需要使用类就要new一个对象来说,初始化时分配内存空间,不使用了还要垃圾回收,简直是节俭的代表。
- 懒汉式(线程不安全)
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
实例唯一:
1、私有化静态实例,带有static关键字的属性在每一个类中都是唯一的,带有private关键字的属性必须提供访问实例的方法。
2、私有化构造函数,限制客户端随意创建实例,保证没有其他实例被创建。
3、提供一个访问该实例的方法getInstance,这个方法必须是静态的,因为我们的实例是静态的。
4、只初始化一次,当唯一实例为null的时候,其他时候直接返回实例
- 懒汉式(线程安全)
public class Singleton {
private static Singleton singleton = null;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
同步getInstance访问方法,效率不高。
- 饿汉式(线程安全)
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return singleton;
}
}
简单易理解且安全。
- 双重锁定
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static Singleton getInstance() {
if (singleton == null) {
synchronized(Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
只同步创建实例的代码块,而且这个代码块执行的次数不会多,当然经常只有一次,效率比较高。
- 静态内部类
public class Singleton {
private static class SingletonHolder {
private static Singleton singleton = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return SingletonHolder.singleton;
}
}
用内部类保存唯一的实例,另外好处是lazy loading(延迟加载),只有使用时才会实例化。
- 枚举
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws Exception {
EnumSingle instance1 = EnumSingle.INSTANCE;
Constructor<EnumSingle> dec = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
dec.setAccessible(true);
EnumSingle instance2 = dec.newInstance();
// EnumSingle instance2 = EnumSingle.INSTANCE;
System.out.println(instance1);
System.out.println(instance2);
}
}