单例模式(饿汉、懒汉)高频面试考点
单例模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
- 3、单例类必须给所有其他对象提供这一实例。
饿汉模式(初始就直接创建好)
类加载的时候实例创建并初始化好了,所以是线程安全的。
//外界不能 new 这个类,所以用 static 来修饰字段和方法 //不允许在类外修改创建的实例,所以实例用 private 声明 public class Singleton { private Singleton(){} private static Singleton singleton=new Singleton();//直接创建好 public static Singleton getInstance(){ return singleton; }
懒汉模式(需要时再创建)双重检测保证线程安全
singleton = new Singleton();
该语句非原子操作,实际是三个步骤。
- 1.给singleton分配内存;
- 2.调用 Singleton 的构造函数来初始化成员变量;
- 3.将给singleton对象指向分配的内存空间(此时singleton才不为null);
必须使用volatile保证执行顺序,比如三个步骤重排序后为1 3 2
,这样第一个线程初始化对象到一半,第二个线程来发现已经不是null了就直接返回了 实际上该对象此时还没有完全初始化 可能会出现这个问题。
synchronized
使用Singleton
类的Class对象作为锁对象,当多个线程同时访问getInstance()
方法时,只有一个线程能够进入同步代码块实例化Singleton类,保证了单例的唯一性。
public class Singleton { private Singleton(){} private static volatile Singleton singleton=null; public static Singleton getInstance(){ if(singleton==null){//第一次判断是为了提升效率,先判断若不为null,锁也没必要抢,抢锁开销是很大的 synchronized (Singleton.class){ if(singleton==null){ singleton=new Singleton(); } } } return singleton; } }