简介
单例模式 有饿汉式 & 懒汉式 等等.
参考链接
https://www.bilibili.com/video/BV1K54y197iS
饿汉式
简单来说, 一上来就把所有的资源进行了申请, 优点, 简单. 缺点, 如果资源比较大, 容易浪费资源.
懒汉式
需要的时候, 才会去申请资源.
code
饿汉式, 非线程安全
public class Hungry {
private Hungry(){}
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance() {
return HUNGRY;
}
}
懒汉式, 非线程安全
public class LazyMan {
private LazyMan(){}
private static LazyMan lazyMan;
private static LazyMan getInstance() {
if(lazyMan == null){
lazyMan = new LazyMan(); // 需要的时候才会去申请资源.
}
return lazyMan;
}
}
静态内部类实现的单例模式 非线程安全
public class Holder {
private Holder() {
}
public static Holder getInstance() {
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER = new Holder();
}
}
懒汉式, 线程安全
package single;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
/**
* Created by lee on 2021/5/30.
*/
public class LazyManThread {
private static boolean qingjiang = false;
private LazyManThread(){
synchronized (LazyManThread.class){
if(qingjiang == false){ // 防止反射造成的单例失效.
qingjiang = true;
}else{
throw new RuntimeException("不要试图使用反射破坏异常");
}
if(lazyMan != null){ // 防止反射造成的单例失效.
throw new RuntimeException("不要试图使用反射破坏异常");
}
}
System.out.println(Thread.currentThread().getName() + "OK");
}
private static LazyManThread lazyMan;
private static LazyManThread getInstance() {
// DCL 懒汉式 双重检测锁
if(lazyMan == null) {
synchronized (LazyManThread.class){ // 加锁
if(lazyMan == null){
lazyMan = new LazyManThread();
/*
* 1. 分配内存空间
* 2. 执行构造方法, 初始化对象
* 3. 把这个对象指向这个空间
* 123 132 由于这个顺序不一定, 也肯造成线程不安全. 使用双重锁来避免这个问题.
* */
}
}
}
if(lazyMan == null){
lazyMan = new LazyManThread();
}
return lazyMan;
}
// public static void main(String[] args) {
// for(int i=0; i<10; i++){
// new Thread(()->{
// LazyManThread.getInstance();
// }).start();
// }
// }
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//LazyManThread instance = LazyManThread.getInstance();
Field qingjiang = LazyManThread.class.getDeclaredField("qingjiang");
qingjiang.setAccessible(true);
Constructor<LazyManThread> declaredConstructor = LazyManThread.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyManThread instance2 = declaredConstructor.newInstance();
qingjiang.set(instance2, false);
LazyManThread instance3 = declaredConstructor.newInstance();
//System.out.println(instance);
System.out.println(instance2);
System.out.println(instance3);
}
}
TIPS
对于使用enum的对象来说, 可以一定程度上保证进行单例模式
package single;
/**
* Created by lee on 2021/5/30.
*/
// enum使用
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance() {
return INSTANCE;
}
}
class Test{
public static void main(String[] args) {
EnumSingle instance1 = EnumSingle.INSTANCE;
EnumSingle instance2 = EnumSingle.INSTANCE;
System.out.println(instance1);
System.out.println(instance2);
}
}
IDEA自带了一套反编译的功能, 但是不是特别好, 可以使用java 自带的反编译系统.
javap -p XXX.class
也不一定成功, 可以使用 jad 来进行反编译. 要下一个新代码, 比较繁琐, 暂时不测试了.
---------------------------我的天空里没有太阳,总是黑夜,但并不暗,因为有东西代替了太阳。虽然没有太阳那么明亮,但对我来说已经足够。凭借着这份光,我便能把黑夜当成白天。我从来就没有太阳,所以不怕失去。
--------《白夜行》