您的位置:首页 > 游戏 > 游戏 > 美食网站建设方案_手机crm_个人免费开发网站_线上怎么做推广和宣传

美食网站建设方案_手机crm_个人免费开发网站_线上怎么做推广和宣传

2025/1/14 19:53:53 来源:https://blog.csdn.net/lft18/article/details/144174158  浏览:    关键词:美食网站建设方案_手机crm_个人免费开发网站_线上怎么做推广和宣传
美食网站建设方案_手机crm_个人免费开发网站_线上怎么做推广和宣传

单例可以说是设计模式中最简单的一种模式。但任何一种设计模式都是普遍经验的总结,都有值得思考的地方。所以单例也并不简单,下面让我们慢慢了解它。

        单例顾名思义这个类只有一个实例。要做到这点,需要做到以下几点:

        (1)构造器私有化

        (2)实例只在类内部创建,并且只会创建一次

        (3)提供静态方法以供外部获取单例对象

        单例有很多种实现方式:

        先介绍两种最简单的:懒汉式和饿汉式

(一)懒汉式:顾名思义,这个单例很懒,懒者做事就慢。所以单例对象是等要用的时候再进行实例化的。下面是一个简单的例子

public final class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (Objects.isNull(instance)) {instance = new Singleton();}return instance;}
}

(二)饿汉式:我们经常听到老一辈说别人吃饭很急,就会说“像个饿死鬼投胎一样”,所以饿汉表现就比懒汉显得急迫,在类加载时就开始实例化。

public final class Singleton {private static final Singleton SINGLETON = new Singleton();private Singleton() {}public static Singleton getSingleton() {return SINGLETON;}
}

        那么这两种有什么区别呢?

        我们应该注意到,单例因为在程序中只有一个实例,所以是线程共享的。那么肯定是在多线程环境下。而懒汉模式是线程不安全的,想象一下多个线程同时在单例还没实例化时进入,那么Objects.isNull(instance)判断为true,从而都会创建实例然后返回,那么有可能返回的是不同的单例。所以懒汉模式几乎不会使用,以此就衍生了线程安全的懒汉模式(这个稍后再介绍)

        而饿汉模式虽然因为类加载只会发生一次,而保证了线程安全。但可能会造成内存浪费。比如单例中可能定义了一个常量,而常量在业务场景中可能先于获取单例使用,那么在常量使用时就会进行单例实例化,如下面代码所示:

public final class Singleton {private static final Singleton SINGLETON = new Singleton();public static final String SINGLETON_CONTENT = "singleton content";private Singleton() {System.out.println("Singleton intance");}public static Singleton getSingleton() {return SINGLETON;}public static void main(String[] args) {System.out.println(Singleton.SINGLETON_CONTENT);}
}

(三)线程安全的懒汉式

        想要线程安全,我们首先想到的就是加synchronized锁,保证它的线程安全。于是就有了下面的实现

public final class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (Objects.isNull(instance)) {instance = new Singleton();}return instance;}
}

        但这种方式虽然线程安全了,但它的锁是方法级的。意味着每次获取实例就会加锁,性能却成了问题。于是又再次进化,有了双重校验锁的方式,可以实现高性能且安全的单例模式。

(四)双重校验锁

        上面已经说道双重校验锁是进化版的线程安全且高性能的懒汉模式。所以它也是需要用到的时候再实例化,但它是线程安全的。那么它是怎么做到的呢?我们直接上代码:

public final class Singleton {private static volatile Singleton instance;private Singleton() {System.out.println("Singleton intance");}public static Singleton getInstance() {// 第一次校验if (instance == null) {synchronized (Singleton.class) {// 第二次校验if (instance == null) {instance = new Singleton();}}}return instance;}
}

        如上代码所示,所谓双重检验锁,就是以两次校验+synchronized加锁方式实现的。第一次校验是基于性能考虑,避免每次都进行加锁,因为只有还没实例化时这个短暂且特殊的场景是需要加锁的,大部分时候都是直接返回实例就行。而第二次校验则是保证实例只会创建一次。

         另外这里有个关键点,instance单例缓存是加了volatile关键字。这是用到了volatile中的其中一个特性--禁止指令重排,想了解更多关于volatile关键字,可以参看我的另一篇《浅谈volatile》

        因为实例的创建实际会分为三个步骤

        (1)分配内存

        (2)初始化对象

        (3)将对象指向刚分配的内存空间

        如果实例是按这个顺序执行,那么不加volatile,范围的单例也是完成初始化的实力,并无影响。但因为编译器优化,可能会把因为初始化放到最后,提前先将对象指向刚分配的内存空间。那么在单例还没初始化完成时,其他线程进入获取单例时,引用对象就不是空,而提前获取到还没初始化完成的单例引用,就可能会导致后面的业务逻辑出错。

(五)静态内部类

public final class Singleton {private Singleton() {System.out.println("Singleton intance");}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}public static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}}

静态内部类也是懒加载的模式,但它的实现更优雅,是我比较推荐的方式。它利用静态内部类可以访问外部类私有构造器的特性,将单例的实例化延迟到静态内部类类加载时,保证了单例的线程安全。而这个静态内部类只会在获取单例的时候加载,所以也是懒加载。

(六)枚举方式

public enum Singleton {INSTANCE;Singleton() {// 初始化}
}

        枚举方式实现也很简单,但却最安全,因为它是反序列化。这个是前面的方式做到的。

        上面介绍了六种单例实现方式。除了第一和第三种的懒汉式不推荐使用外,其他可以根据实际需要选择。比如通常单例比较简单,那么通常饿汉模式就可以满足。需要延迟加载,那么双重校验锁、静态内部类、枚举类都可以。如果涉及到序列化,那么枚举就是唯一选择了。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com