为什么单例模式经常会被在面试中问到?
答案很简单单例模式是23种设计模式中最容易使用代码实现的。
你能想到的实现方法有哪些呢?
1、饿汉式
/**
* @author 冷,静
* 为什么称之为饿汉式呢?
* 那是因为对象随着类的加载就已经创建了,有点迫不及待的样子
*/
public class Single1 {
//1、构造方法私有化
private Single1() {}
//2、创建对象
private static Single1 single = new Single1();
//3、对外提供公共的访问方法
public static Single1 getInstance() {
return single;
}
}
2、懒汉式
public class Single1 {
//1、构造方法私有化
private Single1() {}
//2、创建对象
private static Single1 single = null;
//3、对外提供公共的访问方法
public static Single1 getInstance() {
if (single == null) {
single = new Single1();
}
return single;
}
}
但是这两种方法都有各自的弊端
首先懒汉式存在线程同步的问题,比如说A线程和B线程同时判断single是否为null,A线程先进入,但是还没有创建对象,那么此时single还是为null,那么B线程也进入判断体准备创建对象,此时A线程已经创建Single对象,紧接着B线程也创建了Single对象,那么单例模式就被打破了。
接下来改进一下
改进版懒汉式单例模式
public class Single{
private static Single single = null;
private Single(){}
public static Single getInstance() {
if (single == null) {
synchronized (Single.class) {
if (single == null) {
single = new Single();
}
}
}
return single;
}
}
改进的方式增加了双重校验锁,避免了线程同步的问题,但是不管如何改进,只要第一步是构造方法私有化,都无法真正的实现单例模式,因为我可以通过反射来调用私有的构造方法创建对象,这就打破了单例模式。
反射打破单例:
public void test13() {
try {
for (int i = 1; i < 10; i++) {
Class clazz = Class.forName("domain.Single");
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
System.out.println(constructor.newInstance());
}
} catch (Exception e) {
e.printStackTrace();
}
}
3、静态内部类
public class Single{
private Single(){}
private static class Instance{
private static Single single = new Single();
}
private static Single getInstance() {
return Instance.single;
}
}
静态内部类随着类的加载而加载,并且只加载一次,所以他是单例的。
那么怎样才能实现真正的单例模式呢??
下篇文章将会详细介绍。