设计模式 您所在的位置:网站首页 单例模式两种实现的优缺点 设计模式

设计模式

2023-03-13 16:43| 来源: 网络整理| 查看: 265

前言: 👏作者简介:我是笑霸final,一名热爱技术的在校学生。 📝个人主页:个人主页1 || 笑霸final的主页2 📕系列专栏:计算机基础专栏 📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀 🔥如果感觉博主的文章还不错的话,👍点赞👍 + 👀关注👀 + 🤏收藏🤏

在这里插入图片描述

在这里插入图片描述

目录 一、单例模式定义特点 二、单列模式分类三、饿汉式【可用】3.1饿汉式(静态常量)3.2饿汉式(静态代码块) 四、懒汉式【不可用】4.1懒汉式(线程不安全)【不可用】4.2懒汉式(线程安全,同步方法)【不可用】4.3 懒汉式(线程安全 ,同步代码块)【不可用】 五、双重检查volatile 六、静态内部类七、枚举八、适用场景:

一、单例模式定义

单例模式(Singleton Pattern):属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例

特点 a、单例类只能有一个实例。b、单例类必须自己创建自己的唯一实例。c、单例类必须给所有其他对象提供这一实例。单例模式保证了全局对象的唯一性,比如系统启动读取配置文件就需要单例保证配置的一致性。 二、单列模式分类

设计模式代码仓库

1.饿汉式(静态常量)【可用】

2.饿汉式(静态代码块)【可用】

饿汉式都可能造成内存的浪费

3.懒汉式(线程不安全)【不可用】

4.懒汉式(线程安全,同步方法)【不可用】

5.懒汉式(线程安全,同步代码块)【不可用】[

6.双重检查【推荐使用】

7.静态内部类【推荐使用】

8.枚举【推荐使用】[枚举]

三、饿汉式【可用】

下面两种方式都可用 但是都可能造成内存的浪费

3.1饿汉式(静态常量) 饿汉式(静态变量)【可用】 ====================================================================优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了步问题缺点:在类装载的时候就完成实例化,没有达到Lazy Loading(懒加载)的效果。如至终从未使用过这个实例,则会造成内存的浪费 class Singleton1{ /** * 1.构造器私有化,防止外部new */ private Singleton1(){} /** * 在内部创建实例对象 * 在内加载的时候创建对象实例 */ private final static Singleton1 instance=new Singleton1(); /** * 对外提供一个共有的静态方法返回这个实例 */ public static Singleton1 getInstance(){ return instance; } } 3.2饿汉式(静态代码块) 饿汉式(静态代码块)【可用】================================================================优缺点:和饿汉式(静态变量)类似只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例。优缺点和上面是一样的。 class Singleton2{ /** * 1.构造器私有化,防止外部new */ private Singleton2(){} /** * 在静态代码块中创建实例对象 */ private static Singleton2 instance; static { instance=new Singleton2(); } /** * 对外提供一个共有的静态方法返回这个实例 */ public static Singleton2 getInstance(){ return instance; } } 四、懒汉式【不可用】 4.1懒汉式(线程不安全)【不可用】 懒汉式(线程不安全 )【不可用】========================================================================优点:起到了Lazy Loading的效果,但是只能在单线程下使用。缺点:如果在多线程下,一个线程进入了if (singleton == null)判断语块,还未往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例在多线程环境下不可使用这种方式 class Singleton3{ private Singleton3(){} private static Singleton3 instance; /** * 提供一个静态公有方法,当使用该方法时。才去创建instance */ public static Singleton3 getInstance(){ if(instance==null){ //没有创建才去创建 instance = new Singleton3(); } //返回实例 return instance; } } 4.2懒汉式(线程安全,同步方法)【不可用】 懒汉式(线程安全 ,同步方法)【不可用】========================================================================优点:解决了线程不安全问题缺点:效率太低了,每个线程在想获得类的实例时候,执行getlnstance()方法都要‘synchronized同步’。而其实这个方法只执行一次实例化代码就够了,后面的想获得该直接return就行了。方法进行同步效率太低结论:在实际开发中,效率低 不推荐使用这种方式 class Singleton4{ private Singleton4(){} private static Singleton4 instance; /** * 提供一个静态公有方法,加入了同步处理的代码 ,解决线程安全问题 * 当使用该方法时。才去创建instance */ public static synchronized Singleton4 getInstance(){ if(instance==null){ //没有创建才去创建 instance = new Singleton4(); } //返回实例 return instance; } } 4.3 懒汉式(线程安全 ,同步代码块)【不可用】 懒汉式(线程安全 ,同步代码块)【不可用】========================================================================但是这种同步并不能起到线程同步的作用。跟第Singleton3实现方式遇到的情形一致,假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。 class Singleton5{ private Singleton5(){} private static Singleton5 instance; /** * 提供一个静态公有方法,加入了同步处理的代码 ,解决线程安全问题 * 当使用该方法时。才去创建instance */ public static Singleton5 getInstance(){ if(instance==null){ synchronized(Singleton5.class){ instance = new Singleton5(); } } //返回实例 return instance; } } 五、双重检查 双重检查=========================================================================

优点说明:

Double-Check概念是多线程开发中常使用到的,如代码中所示,我们进行次if (singleton == null)检查,这样就可以保证线程安全了这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton =null)直接return实例化对象,也避免的反复进行方法同步线程安全;延迟加载;效率较高结论: 在实际开发中,推荐使用这种单例设计模式 class Singleton6{ private static volatile Singleton6 instance; private Singleton6(){} /** * 提供一个静态公有方法,加入双重检查的代码 ,解决线程安全问题,同时解决懒加载问题 * 也保证了效率 */ public static synchronized Singleton6 getInstance(){ if(instance==null){ synchronized(Singleton6.class){ if(instance==null){ instance = new Singleton6(); } } } //返回实例 return instance; } } volatile

volatile 是Java提供的一种轻量级的同步机制。Java 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量,相比于synchronized(synchronized通常称为重量级锁),volatile更轻量级,因为它不会引起线程上下文的切换和调度。但是volatile 变量的同步性较差(有时它更简单并且开销更低),而且其使用也更容易出错。

下面简单总结一下volatile的作用:

它会强制将对缓存的修改操作立即写入主存,让所有的线程可见;

它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;

如果是写操作,它会导致其他CPU中对应的缓存行无效。

六、静态内部类 这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。 class Singleton7 { private Singleton7() { } /** * 静态内部类 */ private static class SingletonInstance { private static final Singleton7 INSTANCE = new Singleton7(); } public static Singleton7 getInstance() { return SingletonInstance.INSTANCE; } } 特点:1.外部类装载时 静态内部类不会立即被装载2.调用getInstance() 静态内部类才会被装载而且只会装载一次优点:避免了线程不安全,延迟加载,效率高。 七、枚举

借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象

public class Enumeration { public static void main(String[] args) { Singleton singleton1 = Singleton.INSTANCE; Singleton singleton2 = Singleton.INSTANCE; System.out.println(singleton1==singleton2); System.out.println(singleton1.hashCode()); System.out.println(singleton2.hashCode()); } } /** * 枚举======================== * * 借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象 */ enum Singleton{ //属性 INSTANCE; public void sayOK(){} }

在这里插入图片描述

八、适用场景:

单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。如:

需要频繁实例化然后销毁的对象。创建对象时耗时过多或者耗资源过多,但又经常用到的对象。有状态的工具类对象。频繁访问数据库或文件的对象。

功有所不全,力有所不任,才有所不足。欢迎大家指正文中错误 设计模式代码仓库 欢迎start====》设计模式代码仓库



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有