Java设计模式 - 你真的会单例吗?

本文深入解析单例模式,一种常用的设计模式,确保类只有一个实例。详细介绍六种实现方式:饿汉式、懒汉式、DCL、静态内部类、枚举和容器管理,对比其线程安全性和性能。

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

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。

单例的实现方式(6类)

饿汉式:

/**
 * 饿汉单例
 */
public class SingleDog {

    // 静态对象,类加载就创建
    private static final SingleDog dog = new SingleDog();

    // 私有的构造方法
    private SingleDog() {
    }

    // 获取静态对象方法
    public static SingleDog getSingleDog() {
        return dog;
    }
}

类加载的时候就创建实例,是最简单的单例实现方式,确保线程安全。

懒汉式:

/**
 * 懒汉单例
 */
public class SingleDog {

    // 静态对象
    private static SingleDog dog = null;

    // 私有的构造方法
    private SingleDog() {
    }

    // 获取静态对象方法
    public static synchronized SingleDog getSingleDog() {

        if (dog == null) {
            dog = new SingleDog();
        }
        return dog;
    }
}

类加载时候不创建实例,在首次调用的时候创建,synchronized进行同步控制,确保线程安全,但多线程调用每次都需要同步,有性能问题。

懒汉模式的扩展:双检查上锁方式,Double Check Lock(DCL):

/**
 * DCL单例
 */
public class SingleDog {

    // 静态对象
    private static SingleDog dog = null;

    // 私有的构造函数
    private SingleDog() {
    }

    // 获取静态对象方法
    public static SingleDog getSingleDog() {

        if (dog == null) {
            synchronized (SingleDog.class) {
                if (dog == null) {
                    dog = new SingleDog();
                }
            }
        }
        return dog;
    }
}

DCL在一定程度上解决懒汉模式下的性能问题,将同步控制放在创建实例代码中,但是《Java 并发编程实践》上指出,这种优化是“丑陋的”,在特殊情况下会失效。(个人觉得看完其他实现方式,DCL真的不是很好)

静态内部类方式(推荐):

/**
 * 静态内部类单例
 */
public class SingleDog {

    // 私有的构造方法
    private SingleDog() {
    }

    // 静态内部类
    private static class SingleDogHolder {
        private static final SingleDog dog = new SingleDog();
    }

    // 获取静态内部类的静态对象方法
    public static SingleDog getSingleDog() {

        return SingleDogHolder.dog;
    }

}

静态内部类的方式,在类加载的时候不会创建实例对象,当第一次调用getSingleDog获取单例的时候才会加载内部类,并实例化dog,完美地将实例化交由Java虚拟机控制,确保线程安全,优化性能。

枚举方式:


public class SingleDog {

    /**
     * 枚举单例
     */
    public enum SingleDogEnum {
        DOG;
        private SingleDog singleDog;

        private SingleDogEnum() {
            singleDog = new SingleDog();
        }

        // 获取单例
        public SingleDog getSingleDog() {
            return singleDog;
        }
    }
}

第一次看到,个人我也是懵逼...还有这操作;说是利用了枚举的特性,有待研究

容器管理方式:

/**
 * 容器管理方式
 */
public class SingleDogManager {

    // Map容器
    private static Map<String, Object> singleDogMap = new HashMap<>();

    // 私有的构造方法
    private SingleDogManager() {
    }

    // 加入Map容器管理
    public static void registerSingleDog(String key, Object instance) {
        if (!singleDogMap.containsValue(key)) {
            singleDogMap.put(key, instance);
        }
    }

    // 获取单例
    public static Object getSingleDog(String key) {
        return singleDogMap.get(key);
    }
}

容器管理方式很容易理解,程序初始化的时候将单例统一加入容器,由容器进行统一管理,后续使用必须通过容器获取单例,既屏蔽单例的相关代码,又保证线程安全。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值