1 概念
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
实现方法:
(1) 构造器私有化 。
(2) 类的内部创建对象。
(3) 向外暴露一个静态的公共方法。
2 饿汉式
优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。
缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费
public class HungrySingleton {
private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
3 懒汉式
懒汉式单例的特点是:被外部类调用的时候内部类才会加载
3.3 类锁
public class LazySingleton {
private static LazySingleton lazySingleton = null;
private LazySingleton() {
}
/**
* 类锁,线程安全,锁粒度较高
*/
public static synchronized LazySingleton getInstance() {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
3.2 双重检查
public class LazyDoubleCheckSingleton {
private static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
private LazyDoubleCheckSingleton() {
}
/**
* 双重检查,类锁,锁粒度较低
*/
public static LazyDoubleCheckSingleton getInstance() {
if (lazyDoubleCheckSingleton == null) {
synchronized (LazyDoubleCheckSingleton.class) {
if (lazyDoubleCheckSingleton != null) {
return lazyDoubleCheckSingleton;
}
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
return lazyDoubleCheckSingleton;
}
}
return lazyDoubleCheckSingleton;
}
}
3.3 内部类
public class LazyInnerClassSingleton {
private LazyInnerClassSingleton() {
}
/**
* 内部类特性,当外部调用时,内部类初始化
*/
public static LazyInnerClassSingleton getInstance() {
return Lazyholder.LAZY;
}
private static class Lazyholder {
private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
}
}
PS: 反射破坏单例模式
public class ReflectDestoryDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = LazyDoubleCheckSingleton.class;
Constructor<?> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Object o1 = constructor.newInstance();
LazyDoubleCheckSingleton o2 = LazyDoubleCheckSingleton.getInstance();
System.out.println(o1 == o2);
}
}
4 注册式单例
public class ContainerSingleton {
private ContainerSingleton() {
}
private static Map<String, Object> ioc = new ConcurrentHashMap<>();
public static Object getBean(String className) {
synchronized (ioc) {
if (!ioc.containsKey(className)) {
Object obj = null;
try {
obj = Class.forName(className).newInstance();
ioc.put(className, obj);
} catch (Exception e) {
e.printStackTrace();
}
}
return ioc.get(className);
}
}
}