单例模式及双重锁定了解一下
今天来写写单例吧,其实之前设计模式也看了很多,但是平常不太用到,而且不注意做笔记,所以总是反反复复会忘记,最近在准备面试,那再看一遍总结一下吧。
首先单例模式就是说一个类只能有一个实例对象。
单例模式有两种实现方法:饿汉模式和懒汉模式
饿汉模式:在类加载时就完成了初始化,所以类加载速度比较慢,但是获取对象速度比较快
因为类加载时已经完成了初始化,所以不需要判断对象是否为空,不需要同步
1 //饿汉模式示例代码 2 Class Single{ 3 private static Single s=new Single();//类加载时已进行初始化。s为私有静态成员变量 4 private Single(){}//构造方法为私有的,使得其他类无法通过new产生对象 5 public static Single getInstance(){ 6 return s; 7 } 8 }
懒汉模式:在类加载时不需要创建实例,在第一次调用时再创建
1 Class LazySingle{ 2 private static LazySingle ls; 3 private LazySingle(){} 4 public static LazySingle getInstance(){ 5 if(ls==null){ 6 ls=new LazySingle(); 7 } 8 return ls; 9 } 10 }
懒汉模式的问题在于不同步,如果有多个线程同时掉用getInstance方法时,无法保证单例。
此时可以在getInstance方法上加sychonized锁进行同步,也就是将上述代码第四行变为public static sychonized LazySingle getInstance(){
但是直接在方法上加锁势必会影响性能,因为实例对象如果不为空可以不用锁,直接返回已有实例就可以了。所以就有了双重锁定,先上代码再解释。
Class LazySingle{ private static LazySingle ls; private static Object o=new Object(); private LazySingle(){} public static LazySingle getInstance(){ if(ls==null){ sychonized(o){ if(ls==null) ls=new LazySingle(); } } resturn ls; } }
个人认为叫双重锁定不如叫双重判断来的直接。
首先为了不影响性能,仅在ls为空时加锁,这就是第一层判断的作用。
但是仅有第一层判断就足够了吗?试想现在有两个线程同时到达第一层判断,则两个线程都可以通过第一层判断,这时就需要加锁进行同步,一个一个进,先到达的线程执行第二层判断,此时ls为null,则进行实例化。执行后,后达到的线程再执行第二层的判断,此时发现ls已经不为空了,所以直接返回ls.综上所述,第一层判断是为了判断是否需要加锁,第二层判断是为了判断是否需要进行实例化
另外再说为什么要新建一个对象来加锁,因为在加锁时ls还未进行实例化,即实例还不存在,所以只能通过新建一个对象进行实例化。