饿汉模式
public class HungrySingle {
private static HungrySingle single = new HungrySingle();;
// 私有化构造器,不可外部访问,但是反射可进行调用,手动判断,只允许创建一次
private HungrySingle() {
if (null != single) {
throw new RuntimeException("不可手动创建单例对象");
}
}
public static HungrySingle getInstance() {
return single;
}
}
缺点:饿汉模式将实例创建,要时未有线程使用则内存浪费
枚举单例
public enum SingleEnum {
INSTANCE;
public static SingleEnum getInstance() {
return INSTANCE;
}
}
内部类单例-懒加载
public class SingleInnerClass {
private static SingleInnerClass single;
// 私有化构造器,不可外部访问,但是反射可进行调用,手动判断,只允许创建一次
private SingleInnerClass() {
if (null != single) {
throw new RuntimeException("不可手动创建单例对象");
}
}
public static SingleInnerClass getInstance() {
return SingleInnerClass.Single.single;
}
// 内部类在使用时进行加载--懒加载
private static final class Single {
private static SingleInnerClass single = new SingleInnerClass();
}
}
饱汉模式
public class Single {
private static Single single;
// 私有化构造器,不可外部访问,但是反射可进行调用,手动判断,只允许创建一次
private Single() {
if (null != single) {
throw new RuntimeException("不可手动创建单例对象");
}
}
public static Single getInstance() {
if (null == single) {
single = new Single();
}
return single;
}
public static void main(String[] args) {
System.out.println(Single.getInstance());
}
}
缺点:多线程下,可能会出现创建多个实例对象情况
双重检查单例-推荐
public class SingleDoubleCheck {
private static volatile SingleDoubleCheck single;
// 私有化构造器,不可外部访问,但是反射可进行调用,手动判断,只允许创建一次
private SingleDoubleCheck() {
if (null != single) {
throw new RuntimeException("不可手动创建单例对象");
}
}
public static SingleDoubleCheck getInstance() {
if (null == single) {
synchronized (Single.class) {
if (null == single) {
single = new SingleDoubleCheck();
}
}
}
return single;
}
}
最终优化-容器模式
public class SingleIoc {
// 反射创建对象,只允许创建一个并且存储
public SingleIoc(String className) {
if (ioc.containsKey(className)) {
throw new RuntimeException("不可手动创建单例对象");
}
}
// 单例池
private static Map ioc = new ConcurrentHashMap();
public static Object getInstance(String className) {
if (!ioc.containsKey(className)) {
synchronized (ioc) {
Object obj = null;
try {
obj = new SingleIoc(className);
ioc.put(className, obj);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
} else {
return ioc.get(className);
}
}
}