单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
- 3、单例类必须给所有其他对象提供这一实例。
单例模式它有以下几个要素:
- 1.私有的构造方法。
- 2.指向自己实例的私有静态引用。
- 3.以自己实例为返回值的静态的公有的方法。
饿汉式单例模式
public class Hungry {
private final static Hungry hungry = new Hungry();
private Hungry() {}
public static Hungry getHungry() {
return hungry;
}
}
饿汉式单例模式的好处:
它是在类加载的时候就立即初始化,并且创建单例对象,没有加任何的锁、绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题,执行效率比较高,在用户体验上来说,比懒汉式更好。
饿汉式单例模式的缺点:
类加载的时候就初始化,不管你用还是不用,都占着空间浪费了内存,有可能占着茅坑不拉屎。
懒汉式单例模式
public class SafeDoubleCheckedLocking {
//volatile 防止指令重排序 内存可见性、
private static volatile SafeDoubleCheckedLocking safeDoubleCheckedLocking = null;
private SafeDoubleCheckedLocking() {}
public static SafeDoubleCheckedLocking getInstance() {
if(safeDoubleCheckedLocking == null) {
synchronized (SafeDoubleCheckedLocking.class) {
// 第一个线程已经创建了,第二个线程无需在创建 故此第二重判断
if(safeDoubleCheckedLocking == null) {
//这里有指令重排序的可能
/**
* memory = allocate(); //1:分配对象的内存空间
* ctorInstance(memory); //2:初始化对象
* instance = memory; //3:设置instance指向刚分配的内存地址
* <p>
* memory = allocate(); //1:分配对象的内存空间
* instance = memory; //3:设置instance指向刚分配的内存地址
* 注意,此时对象还没有被初始化!
* ctorInstance(memory); //2:初始化对象
*/
safeDoubleCheckedLocking = new SafeDoubleCheckedLocking();
}
}
}
return safeDoubleCheckedLocking;
}
}
懒汉式单例模式的好处:
在使用该类的时候在初始化对象,不会对内存造成浪费。
懒汉式单例模式的缺点:
加synchronized同步锁的,性能就会受到影响。
注:双重检验锁是面试经常提问到的事,大家切记要搞懂。
懒汉式单例内部类模式(算是懒汉式单例模式改进版)
public class LazyPromote {
// private static boolean initialized = false;
//默认使用LazyThree的时候,会先初始化内部类
//如果没使用的话,内部类是不加载的
private LazyThree() {
/*synchronized (LazyThree.class) {
if (initialized == false) {
initialized = !initialized;
} else {
throw new RuntimeException("单例已被侵犯");
}
} */
}
//每一个关键字都不是多余的
//static 是为了使单例的空间共享
//final 保证这个方法不会被重写,重载
public static final LazyPromote getInstance() {
//在返回结果以前,一定会先加载内部类
return LazyHolder.LAZY;
}
//默认不加载
private static class LazyHolder {
private static final LazyThree LAZY = new LazyPromote();
}
}
懒汉式单例内部类模式改进版
特点:在外部类被调用的时候内部类才会被加载,内部类一定是要在方法调用之前初始化,巧妙地避免了线程安全问题这种形式兼顾饿汉式的内存浪费,也兼顾synchronized性能问题,完美地屏蔽了这两个缺点,史上最牛B的单例模式的实现方式.
注册登记式单例
public class BeanFactoryNew {
private BeanFactoryNew() {
}
//线程安全
private static Map<String, Object> ioc = new ConcurrentHashMap();
public static synchronized <T> T getBean(Class<T> className) {
if (!ioc.containsKey(className.getName())) {
T obj = null;
try {
obj =className.newInstance();
ioc.put(className.getName(), obj);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
} else {
return (T)ioc.get(className.getName());
}
}
}