java单例模式

java 单例模式

饿汉式

简介: 一上来就加载

/**
 * @author pikaqiu
 * @version 1.0
 * @date 2020/12/29 9:46
 * 饿汉式
 */
public class Hungry {

    // 假如
    // 十分的浪费空间
    private byte[] bytes1 = new byte[1024*1024];
    private byte[] bytes2 = new byte[1024*1024];
    private byte[] bytes3 = new byte[1024*1024];
    private byte[] bytes4 = new byte[1024*1024];

    private Hungry() {}

    private final static Hungry hungry = new Hungry();

    public static Hungry getInstance() {
        return hungry;
    }
}

懒汉式

简介: 使用时在加载

public class LazyMan {

    private LazyMan() {}

    private static LazyMan lazyMan = null;

    public static LazyMan getInstance() {
        if (lazyMan == null) {
            lazyMan = new LazyMan();
        }

        return lazyMan;
    }
}

// 单线程情况下 确实单例ok, 但多线程环境下会出现问题

DCL 懒汉模式

public class LazyMan {
    // 多线程情况下测试
    private LazyMan() {
        System.out.println(Thread.currentThread().getName() + "ok");
    }

    private static volatile LazyMan lazyMan = null;

    // 双重检测锁模式 的 懒汉式单例 DCL懒汉式
    public static LazyMan getInstance() {
        // 加锁
        if (lazyMan == null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    lazyMan = new LazyMan(); // 不是一个原子性操作
                    /**
                     * 1. 分配内存空间
                     * 2. 执行构造方法, 初始化对象
                     * 3. 把对象指向这个空间
                     *
                     * 123
                     * 132 A
                     */
                }
            }
        }

        return lazyMan;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                LazyMan.getInstance();
            }, "Thread——" + i).start();
        }
    }
}

静态内部类实现

public class Holder {

    private Holder() {
    }

    public static Holder getInstance() {
        return InnerClass.HOLDER;
    }

    public static class InnerClass {
        private static final Holder HOLDER = new Holder();
    }
}

反射进行破解

        // 传统
        LazyMan lazyMan1 = LazyMan.getInstance();
        // 反射
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan lazyMan2 = declaredConstructor.newInstance();

解决:

class LazyMan {    
// 多线程情况下测试
    private LazyMan() {
        synchronized (LazyMan.class) {
            if (lazyMan != null) {
                throw new RuntimeException("不要试图用反射来破坏异常");
            }
        }
        System.out.println(Thread.currentThread().getName() + "ok");
    }

    private static volatile LazyMan lazyMan = null;

    // 双重检测锁模式 的 懒汉式单例 DCL懒汉式
    public static LazyMan getInstance() {
        // 加锁
        if (lazyMan == null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    lazyMan = new LazyMan(); // 不是一个原子性操作
                    /**
                     * 1. 分配内存空间
                     * 2. 执行构造方法, 初始化对象
                     * 3. 把对象指向这个空间
                     *
                     * 123
                     * 132 A
                     */
                }
            }
        }

        return lazyMan;
    }
}

破解:

       // 双反射
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan lazyMan1 = declaredConstructor.newInstance();
        LazyMan lazyMan2 = declaredConstructor.newInstance();

解决:(红绿灯模式)

class LazyMan {
private static boolean redAndGreen = false;

    // 多线程情况下测试
    private LazyMan() {
        synchronized (LazyMan.class) {
            if (redAndGreen == false) {
                redAndGreen = true;
            } else {
                throw new RuntimeException("不要试图用反射来破坏异常");
            }
        }
        System.out.println(Thread.currentThread().getName() + "ok");
    }

    private static volatile LazyMan lazyMan = null;

    // 双重检测锁模式 的 懒汉式单例 DCL懒汉式
    public static LazyMan getInstance() {
        // 加锁
        if (lazyMan == null) {
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    lazyMan = new LazyMan(); // 不是一个原子性操作
                    /**
                     * 1. 分配内存空间
                     * 2. 执行构造方法, 初始化对象
                     * 3. 把对象指向这个空间
                     *
                     * 123
                     * 132 A
                     */
                }
            }
        }

        return lazyMan;
    }
}

破坏:

   // 反射
        Field redAndGreen = LazyMan.class.getDeclaredField("redAndGreen");
        redAndGreen.setAccessible(true);

        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan lazyMan1 = declaredConstructor.newInstance();

        redAndGreen.set(lazyMan1, false);

        LazyMan lazyMan2 = declaredConstructor.newInstance();

总结: 可以通过反射破坏私有

查看反射的newInstance 源码得知 不能使用反射来破坏枚举

枚举

enum 是什么?

枚举本身也是一个类,它本身就是单例的, 没有空参的构造方法

枚举单例模式实现

public enum  EnumSingle {
    INSTANCE;

    public static EnumSingle getInstance() {
        return INSTANCE;
    }
}

单例常用场景

  • servlet中每个servlet都是单例
  • 数据库连接池一般都是单例的
  • Spring中每个Bean都是单例的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值