设计模式之单例模式

本文深入解析单例模式的核心概念及其实现方式,包括饿汉式、懒汉式、双重检测锁、静态内部类和枚举单例等五种常见模式。探讨了每种模式的特点、优缺点以及应用场景,如配置文件管理、计数器、文件系统等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例模式

核心:
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
常用场景:
1. windows 系统 任务管理器、回收站

2. 网站计数器

3. 配置文件

4. 操作系统的文件系统

5. spring 中的 bean 默认是单例

...
优点:
减少系统开销
常见的五种单例模式
  1. 主要

    • 饿汉式(线程安全、调用效率高。但是,不能延时加载)
    • 懒汉式(线程安全、调用效率不高。但是可以延时加载)
  2. 其它

    • 双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题。不建议使用)
    • 静态内部类式(线程安全、调用效率高。可以延时加载)
    • 枚举单例(线程安全、调用效率不高。但是可以延时加载,天然防止反射、反序列化漏洞)
问题
  • 反射破解(不包含枚举类)以上几种方式(可以在构造方法中手动抛出异常空值)
1. 饿汉式
/*
 * 饿汉式实现单例模式
 * 
 *  1. 构造方法私有化 
 *  2. 类初始化时,立即加载(希望延时加载,即懒汉式)
 */
public class Singleton {

    // 天然的线程安全,调用效率高。
    private static Singleton singleton = new Singleton();

    private Singleton() {

    }

    public static Singleton getInstance() {
        return singleton;
    }

}
2. 懒汉式
/*
 * 懒汉式 单例模式
 * 
 *  延迟加载,真正用的时候才加载
 */
public class SingletonLazy implements Serializable {

    private static SingletonLazy singleton;

    private SingletonLazy() {
        // 防止反射破解单例模式
        // if (singleton != null) {
        // throw new RuntimeException();
        // }
    }

    // 每次调用都要同步
    // 资源利用率高,并发效率低
    public static synchronized SingletonLazy getInstance() {
        if (singleton == null)
            singleton = new SingletonLazy();
        return singleton;
    }

    // 反序列化时,如果定义了 readResolve 方法则直接返回此方法返回的对象,不需要单独再创建对象
    // private Object readResolve() throws ObjectStreamException {
    // return singleton;
    // }

}
3. 双重检验锁
/*
 * 双重检测锁模式
 */
public class SingletonLock {

    private static SingletonLock singleton;

    private SingletonLock() {

    }

    public static SingletonLock getInstance() {
        if (singleton == null) {
            SingletonLock sl;
            synchronized (SingletonLock.class) {
                sl = singleton;
                if (sl == null) {
                    synchronized (SingletonLock.class) {
                        if (sl == null) {
                            sl = new SingletonLock();
                        }
                    }
                    singleton = sl;
                }
            }
        }
        return singleton;
    }
}

4. 静态内部类
/*
 * 静态内部类实现单例模式
 * 
 *   线程安全并且懒加载
 */
public class SingletonInner {

    private SingletonInner() {

    }

    private static class SingletonInnerClass {
        private static final SingletonInner instance = new SingletonInner();
    }

    public static SingletonInner getInstance() {
        return SingletonInnerClass.instance;
    }
}
5. 枚举类
/*
 * 枚举实现单例
 */
public enum SingletonEnum {

    // 枚举元素,本身就是单例对象,没有懒加载
    INSTANCE;

    public void getInstance() {

    }
}

测试反射、反序列化

/**
 * 测试反射、反序列化破解单例
 * 
 * @author apple
 */
public class Main {

    public static void main(String[] args) throws Exception {

        SingletonLazy instance1 = SingletonLazy.getInstance();
        // SingletonLazy instance2 = SingletonLazy.getInstance();
        //
        System.out.println(instance1);
        // System.out.println(instance2);
        //
        // // 通过反射获取私有构造器
        // Class<SingletonLazy> clz = (Class<SingletonLazy>)
        // Class.forName("com.beng.design.singleton.SingletonLazy");
        // Constructor<SingletonLazy> cons = clz.getDeclaredConstructor(null);
        // cons.setAccessible(true);
        // SingletonLazy instance3 = cons.newInstance();
        // SingletonLazy instance4 = cons.newInstance();
        //
        // System.out.println(instance3);
        // System.out.println(instance4);

        // 通过序列化的方式构造多个对象
        // FileOutputStream fos = new FileOutputStream("a.txt");
        // ObjectOutputStream oos = new ObjectOutputStream(fos);
        // oos.writeObject(instance1);
        // oos.close();
        // fos.close();
        // System.out.println("end");

        ObjectInputStream oin = new ObjectInputStream(new FileInputStream("a.txt"));

        SingletonLazy instance = (SingletonLazy) oin.readObject();
        System.out.println(instance);
    }

}

测试单例模式效率

/**
 * 测试创建单例模式 效率
 * 
 * @author apple
 */
public class Test {

    public static void main(String[] args) throws Exception {

        long start = System.currentTimeMillis();
        int nthreads = 10;
        final CountDownLatch count = new CountDownLatch(nthreads);

        for (int j = 0; j < nthreads; ++j) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 1000000; ++i) {
                        Object obj = SingletonEnum.INSTANCE;
                    }
                    count.countDown();
                }
            }).start();
        }

        long end = System.currentTimeMillis();
        count.await(); // main 线程阻塞,直到count=0
        System.out.println("总耗时:" + (end - start));

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值