单例模式
一个类只允许创建一个对象。
为什么要使用单例
- 处理资源访问冲突(对一个文件,同时写入日志)
- 全局唯一类(配置数据在系统中只保留一份)
应用场景
- 数据库连接池、日志记录类、配置读取
- JDK中的java.lang.Runtime 该类用于管理程序运行期间的信息:memory 和 processor信息
双重检测
//饿汉式不支持延迟加载
//懒汉式并发性能不高,getInstance方法被加了synchronized
//使用双重检测式
public class Singleton{
private static Singleton single;
private Singleton(){}
public static Singleton getInstance(){
if(null == instance){
synchronized(Singleton.class){
if(null == instance) instance = new Singleton();
}
}
return instance;
}
}
指令重排序,可能会导致Singleton对象被new 出来赋值给instance后,还没来得及初始化(执行构造函数中的代码逻辑)就被另一个线程使用了,需要给instance成员变量加上volatile关键值,禁止指重排序。实际上只有低版本的jdk 才会有这个问题,高版本已经在jdk内部通过把对象new操作和初始化操作设为原子操作,解决了这个问题。
静态内部类
public class Singleton{
private Singleton(){}
private static class SingletonHolder{
private static final Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
当外部类被加载的时候并不会创建SingletonHolder实例,只有调用getInstance方法时,才会创建instance, instance的唯一性和创建过程中的线程安全性都是JVM来保证的。
枚举
public enum Singleton{
INSTANCE;
private String name;
public String getName()
return name;
}
public void setName(String name){
this.name = name;
}
}
通过java枚举本身的特性,保证了实例创建的线程安全性和实例的唯一性。