Java设计模式--SingleTon单例模式

本文探讨了Java中的单例模式,包括饿汉式和懒汉式实现,并分析了它们在多线程环境下的问题。通过静态内部类和双重检查锁定等方法,解释了如何确保线程安全并实现延迟加载。最后指出,在实际开发中,饿汉式单例模式更为常见。

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

单例模式在我们日常开发中其实也挺常见的,很多时候我们不喜欢别人对某个类创建太多的实例(亦或者需要频繁创建销毁某个对象,或者创建某个对象比较耗时消耗很多资源),那么我们就可以使用单例模式。单例模式的写法有很多,而有些写法其实纯在问题,那今天就在这篇文章中列举常见的单例写法并进行分析。

首先就是最常见的饿汉式写法:(饿汉是指太饥饿了,急需,所以一上来就先new一个出来)

public class SingleTonFactory {
    private static final SingleTonFactory INSTANCE = new SingleTonFactory();

    private SingleTonFactory() {
    }

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

把构造函数设置为private,防止别人无限制的new出对象,然后我们需要了解一个知识点就是jvm对每个类只会加载一次,用这个static修饰的话,那么这个SingleTonFactory被加载到内存之后,就实例化了一个factory的单例,由此,该方法在jvm中是线程安全的。

还有一种是懒汉式:(就是比较懒,啥时候要啥时候再new)

public class SingleTonFactory {
    private static SingleTonFactory INSTANCE = null;

    private SingleTonFactory() {
    }

    public static SingleTonFactory getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new SingleTonFactory();
        }
        return INSTANCE;
    }
}

其实在单线程中正常使用时是没有啥问题的,但是到了多线程环境下,问题就出来了,如果线程一判断了INSTANCE == null,然后就往下走但是还没new,这时候另一个线程也走到了判断,为null,这时候线程二也往下走,那么线程一和线程二都各自new了一个实例,这就不符合单例模式了。然后就有人给这个单例过程加锁,经过不断的调优,最后变成下面这样的形式:

public class SingleTonFactory {
    private static volatile SingleTonFactory INSTANCE; //volatile保证线程可见性

    private SingleTonFactory() {
    }

    public static SingleTonFactory getInstance() {
        if (INSTANCE == null) {
            synchronized (SingleTonFactory.class) {
                if (INSTANCE == null) {
                    INSTANCE = new SingleTonFactory();
                }
            }
        }
        return INSTANCE;
    }
}

但是因为加锁了,所以执行效率方面肯定会存在一定的影响,本来时为了解决饿汉模式一加载就初始化的问题,结果修改后影响到性能,性价比不够。。。

所以后面有人用静态内部类的特性实现了一种单例:

public class SingleTonFactory {

    private SingleTonFactory() {
    }

    private static class Holder {
        private final static SingleTonFactory INSTANCE = new SingleTonFactory();
    }

    public static SingleTonFactory getInstance() {
        return Holder.INSTANCE;
    }
}

这里用到了jvm类加载的特性:加载一个类时,其内部类不会被加载,当且仅当内部类的静态成员被调用时才会加载内部类,而前面也提到了,jvm加载某个类时只会加载一次,这样一来,该INSTANCE只会被实例一次,保证了线程安全,还实现了懒加载。

发展到后面,出现了一种更牛逼的写法:

public enum  SingleTonFactory {
    INSTANCE;
}

单例模式大致就是以上几种写法了,不过在平时开发中,还是用饿汉式的单例模式比较多一些~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值