单例设计模式

本文深入探讨了单例设计模式的不同实现方式,包括饿汉式、懒汉式、双重检查锁定等,并对比了它们的特点及适用场景。此外还介绍了如何利用静态内部类实现既延迟加载又保证线程安全的单例。

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

单例设计模式

/** 单例设计模式
*
*/
public class SimpleModelController {

/** 饿汉式单利模式   类只被创建一次,所有调用此方法的共享一个类
 **   类被初始化的时候 单利类被加载出来
 */
private static SimpleModelController con = new SimpleModelController();

private SimpleModelController(){}
public static SimpleModelController getInstance(){
    return con;
}


/**
 * 懒汉是单例模式   类有可能被创建多次 但是加上 同步的关键词之后,同步执行方法,同样可避免创建多次类
 * 类被初始化的时候类不加载 ,调用方法的时候加载类;
 */
private static SimpleModelController lazysimpleModelController;
private SimpleModelController(){}   TODO
public static synchronized SimpleModelController getLazyInstance(){
    if (null == lazysimpleModelController) {
        lazysimpleModelController = new SimpleModelController();
    }
    return lazysimpleModelController;
}


/**
 * 双重判定锁
 * 假设有100个线程 双重判定锁会同事执行,而上面懒加载的话 会等待方法执行完毕再进入方法
 * 双重判定算的话,会进入方法 100个线程可以同时判断if 理论只有一个判断时间
 * 如果面对高并发的话 选择双重判定锁
 * volatile 这个关键字 是java1.5  语义禁止指令 重排序优化
 * (双重判定锁 也会出现失败)
 * 在jvm初始化的 会给该对象分配一个内存空间,并且把对象的字段设置成默认值,此时的时候就把当前这个inser
 * 对象分配到一个默认的地址,此时刚好有一个线程来进行调用getDualInstance方法,取到的就是不正确的对象
 * 加上volatile关键字之后 会按照执行顺序执行,等待当前对象初始化完成
 */
private static SimpleModelController inser = null;

private static volatile SimpleModelController inser = null;
private SimpleModelController(){ }  TODO
public static SimpleModelController getDualInstance(){

    if (inser == null) {
        synchronized (SimpleModelController.class){
            if (inser == null) {
                inser = new SimpleModelController();
            }
        }
    }

    return inser;
}

/**
 * 利用java 反射 创建多个单利对象
 * 这里每次运行都会创建心的单利对象,违背了单利模式的原则 不要使用反射产生单利对象
 *
 */
public static void  reflect(){

    try {
        Class c= Class.forName(SimpleModelController.class.getName());
        Constructor  declaredConstructors = c.getDeclaredConstructor();
        declaredConstructors.setAccessible(true);
        SimpleModelController simpleModelController = (SimpleModelController)c.newInstance();

    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

}

}

//
最后一个方法使用反射机制实现了 创建多个单例,对于getDeclaredConstructor 不是太理解 进行了检索;
java 反射使用了getDeclaredConstructor方法,
******** getConstructor()和getDeclaredConstructor()区别:********

getDeclaredConstructor(Class<?>… parameterTypes) 这个方法会返回制定参数类型的所有构造器,包括public的和非public的,当然也包括private的。
getDeclaredConstructors()的返回结果就没有参数类型的过滤了。

再来看getConstructor(Class<?>… parameterTypes)
这个方法返回的是上面那个方法返回结果的子集,只返回制定参数类型访问权限是public的构造器。
getConstructors()的返回结果同样也没有参数类型的过滤。

/**
     * 利用静态内部类 来实现lazy 同时也能保证线程安全
     */
    private static class simpleHerder{
        public static SimpleModelController model = new SimpleModelController();

    }
    private SimpleModelController(){}

    public static SimpleModelController conn(){
        return simpleHerder.model;
    }

这种方式同样利用了类加载机制来保证只创建一个instance实例。它与饿汉模式一样,也是利用了类加载机制,因此不存在多线程并发的问题。不一样的是,它是在内部类里面去创建对象实例。这样的话,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。也就是说这种方式可以同时保证延迟加载和线程安全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值