单例模式分为: 饿汉式单例 和 懒汉式单例 、登记式单例
我们这只讲前两种单例!
一、饿汉式单例
package single;
/**
* Hungry
*
* @author Lizq
* @date 2021/12/22 10:57
* 饿汉式单例
*
* 浪费内存
*/
public class Hungry {
private Hungry() {}
private static final Hungry single = new Hungry();
//静态工厂方法
public static Hungry getInstance() {
return single;
}
}
二、懒汉式单例
package single;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* Lazy
*
* @author Lizq
* @date 2021/12/22 11:01
* 懒汉式单例
* 1、单例类只能有一个实例。
* 2、单例类必须自己创建自己的唯一实例。
* 3、单例类必须给所有其他对象提供这一实例。
*
* synchronized: 具有原子性,有序性和可见性
* volatile:具有有序性和可见性
*
*
*/
public class Lazy {
private Lazy() {
// synchronized (Lazy.class){
if(single!=null){
throw new RuntimeException("不要试图反射破坏异常");
}
// }
System.out.println(Thread.currentThread().getName()+"OK");
}
private volatile static Lazy single=null; //volatile避免指令重排
//DCL double check lazy 双重检查锁
public static Lazy getInstance() {
if (single == null) {
synchronized (Lazy.class){
if (single == null) {
single = new Lazy(); //不是原子性操作
/*
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把这个对象执行这个空间
*
*指令重排
* */
// System.out.println(single);
}
}
}
return single;
}
// 多线程并发
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.
// for (int i = 0; i < 10; i++) {
// new Thread(()->{
// Lazy.getInstance();
// }).start();
// }
//2.
// Lazy s = Lazy.getInstance();
// System.out.println(s);
// Lazy a = Lazy.getInstance();
// System.out.println(a);
//3.反射
Lazy instance = Lazy.getInstance();
Constructor<Lazy> declaredConstructor = Lazy.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
Lazy instance2 =declaredConstructor.newInstance();
System.out.println(instance);
System.out.println(instance2);
}
}
三、总结