设计模式之-单例模式
整个程序有且仅有一个实例,该类负责创建自己的对象同时确保只有一个对象被创建。通常用于在工具类的实现或创建对象需要消耗资源。
特点
类构造器私有
持有自己类型的属性
对外提供获取实例的静态方法
痴汉模式
public class God{
//类加载时就由类加载器加载,此对象不会作为GC ROOTS,永远不会被GC回收
private static God god = new God();
private God(){
}
//私有化构造函数,无法创建此类(也就是不能new)
public static God getGod(){
return this.god;
}
}
- 痴汉模式优点:不用关心多线程问题,类由类加载器放到方法区。
- 缺点:由于不会被GC,造成内存浪费
懒汉模式
public class God {
//初始化时不直接初始化自己
private static God god;
private God(){
}
public static God getGod(){
if(god == null){
god = new God();
}
return god;
}
}
- 优点:不会浪费内存
- 缺点:每次获取时都要初始化,影响速度,且线程不安全
双重锁模式
public class God{
private volatile static God god;
private God(){
}
public static God getGod(){
if(god == null){
synchronized(){
if(god == null){
god = new God();
}
}
}
return god;
}
}
- 优点:线程安全,多线程下保持高性能
- 缺点:延迟加载
说明:双重检查模式进行了两次判断,第一次是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。由于god = new God()在JVM中可能会重排序,多线程下存在风险,使用volatile修饰god实例变量解决该问题。
静态内部类单例模式
public class God{
private God(){
}
public static God getGod(){
return Inner.god;
}
private static class Inner{
private static final God god = new God();
}
}
只有第一次调用getGod方法时,虚拟机才加载Inner并初始化god,只有一个线程可以获得对象的初始化锁,其他线程无法进行初始化,保证对象的唯一性。目前此方式是所有单利模式中最推荐的模式。
注:单例模式是创建型模式,都会新建一个实例,那个一个重要的问题就是反序列化,我们需要重写readResolve方法,让实例保持唯一。