设计模式之单例模式

简介

所谓的单例设计模式,就是采取一定的办法保证整个系统中,对某个类只存在一个对象实例,并且该类只提供一个获取该对象实例的方法,同时这个方法是静态的。 使用场景: 需要频繁的进行创建和销毁的对象、创建对象耗时很多,但是经常使用的对象、频繁访问数据库或文件的对象。

七种实现方式

第一种---饿汉式(静态常量)现方式

所谓饿汉式,通俗来讲就是我饿了,你得给我准备好,我想吃了就直接拿着吃了,别现做~ 过程如下

  • 1、构造器私有化(防止new创建)
  • 2、在类的内部创建对象
  • 3、向外暴露一个静态的公共方法 下面是代码实现
java 复制代码
public class StaticConstant {  
  
    /**  
    * 构造方法私有化  
    */  
    private StaticConstant(){}  

    /**  
    * 静态常量实例对象  
    */  
    private static final StaticConstant staticConstant = new StaticConstant();  

    /**  
    * 对外暴露的静态方法  
    * @return  
    */  
    public static StaticConstant getInstance(){  
        return staticConstant;  
    }  
}

优点

写法简单,类装载的时候就完成了实例化,没有线程安全问题。

缺点

在类装载的时候就完成了实例化,没有达到懒加载的效果,如果没有使用过这个实例,其实就是一种内存浪费。

第二种---饿汉式(静态代码块)实现方式

  • 1、构造器私有化(防止new创建)
  • 2、在类的静态代码块中创建实例对象
  • 3、向外暴露一个静态的公共方法
java 复制代码
public class StaticCodeBlock {  
  
    /**  
    * 构造方法私有化  
    */  
    private StaticCodeBlock(){}  

    /**  
    * 静态常量实例对象  
    */  
    private static StaticCodeBlock staticCodeBlock;  

    /**  
    * 静态代码块  
    */  
    static {  
    staticCodeBlock = new StaticCodeBlock();  
    }  

    /**  
    * 对外暴露的静态方法  
    * @return  
    */  
    public static StaticCodeBlock getInstance(){  
        return staticCodeBlock;  
        }  
    }

优点和缺点和第一种方式一样!!

第三种---线程不安全的懒汉式实现方式

  • 1、构造器私有化(防止new创建)
  • 2、向外暴露一个静态的公共方法
  • 3、在公共方法是完成实例对象的创建,但是需要判断是否已经创建过 代码如下
java 复制代码
public class ThreadNoSafe {  
  
    /**  
    * 构造方法私有化  
    */  
    private ThreadNoSafe(){}  

    /**  
    * 静态常量实例对象  
    */  
    private static ThreadNoSafe threadNoSafe;  

    /**  
    * 对外暴露的静态方法  
    * @return  
    */  
    public static ThreadNoSafe getInstance(){  
        if(threadNoSafe == null){  
            threadNoSafe = new ThreadNoSafe(); 
        }  
        return threadNoSafe;  
    }  
}

优点

起到了懒加载的效果

缺点

只能在单线程的情况下使用,我们可以看到在if(threadNoSafe == null)这行语句中,多线程的环境下,一个线程完成了这个判断,但是还没有执行向下的代码,另一个线程也进来了,也执行判断,判断的结果则也是null,所以就会存在多个线程同时执行创建的情况,那么就会产生多个实例对象,所以实际开发中不要使用这种方式。

第四种---线程安全的懒汉式实现方式

步骤同第三种,但是在getInstance方法上加上sychronized 代码如下

java 复制代码
public class ThreadSafe {  
  
    /**  
    * 构造方法私有化  
    */  
    private ThreadSafe(){}  

    /**  
    * 静态常量实例对象  
    */  
    private static ThreadSafe threadSafe;  

    /**  
    * 对外暴露的静态方法  
    * @return  
    */  
    public static synchronized ThreadSafe getInstance(){  
        if(threadSafe == null){  
            threadSafe = new ThreadSafe();  
        }  
        return threadSafe;  
    }  
}

优点

解决了线程不安全的问题。

缺点

效率太低了,每个线程想要获取类的实例的时候都需要同步。

第五种---线程安全的懒汉式(双重检查)实现方式

过程同四类似,但是sychronized换了位置,代码如下

java 复制代码
public class ThreadSafeDoubleCheck {  
  
/**  
* 构造方法私有化  
*/  
private ThreadSafeDoubleCheck(){}  
  
    /**  
    * 静态常量实例对象  
    */  
    private static ThreadSafeDoubleCheck threadSafeDoubleCheck;  

    /**  
    * 对外暴露的静态方法  
    * @return  
    */  
    public static synchronized ThreadSafeDoubleCheck getInstance(){  
        if(threadSafeDoubleCheck == null){  
            synchronized (ThreadSafeDoubleCheck.class) {  
                if(threadSafeDoubleCheck == null) {  
                    threadSafeDoubleCheck = new ThreadSafeDoubleCheck();  
                }  
            }  
        }  
        return threadSafeDoubleCheck;  
    }  
}

这个是推荐使用的一种方式,我们可以看到这是一个双重检查,尽管第一次判断有多个线程进入,那么进入第二个判断的也只有一个线程,这个线程创建完之后,其他线程进入判断的时候,实例对象就不是空的了,所以是双重检查的单例对象的创建方式是线程安全的,也是推荐使用的。

第六种---静态内部类的实现方式(线程安全)

在类加载时候内部类是不会加载的,而是当调用到内部类的时候才会去加载,同时类加载的时候是线程安全的

  • 1、构造器私有化(防止new创建)
  • 2、在类的内部编写一个内部类,内部类中创建一个当前类的常量对象。
  • 3、向外暴露一个静态的公共方法,返回内部类中的常量对象实例。 代码如下
java 复制代码
public class InnerClass {  
  
    /**  
    * 构造方法私有化  
    */  
    private InnerClass(){}  

    /**  
    * 内部类  
    */  
    private static class SingletonClass{  
        private static final InnerClass instance = new InnerClass();  
    }  

    /***  
    * 对外暴露的static方法  
    * @return  
    */  
    public static InnerClass getInstance(){  
        return SingletonClass.instance;  
    }  
}

JVM帮我们保证了线程安全,同时利用静态内部类的特点实现了延迟加载,推荐使用。

第七种--- 枚举方式实现(线程安全)

借助枚举实现单例,不仅能避免多线程的问题,还能方式反序列化创建新的对象。代码如下

java 复制代码
public enum EnumSingleton {  
  
INSTANCE;  
  
    public void test(){  

    }  
}

推荐使用

相关推荐
追逐时光者5 小时前
推荐 12 款开源美观、简单易用的 WPF UI 控件库,让 WPF 应用界面焕然一新!
后端·.net
Jagger_5 小时前
敏捷开发流程-精简版
前端·后端
苏打水com6 小时前
数据库进阶实战:从性能优化到分布式架构的核心突破
数据库·后端
rongqing20196 小时前
Google 智能体设计模式:人机协同(HITL)
设计模式
间彧7 小时前
Spring Cloud Gateway与Kong或Nginx等API网关相比有哪些优劣势?
后端
间彧7 小时前
如何基于Spring Cloud Gateway实现灰度发布的具体配置示例?
后端
间彧7 小时前
在实际项目中如何设计一个高可用的Spring Cloud Gateway集群?
后端
间彧7 小时前
如何为Spring Cloud Gateway配置具体的负载均衡策略?
后端
间彧7 小时前
Spring Cloud Gateway详解与应用实战
后端
王嘉俊9257 小时前
设计模式--享元模式:优化内存使用的轻量级设计
java·设计模式·享元模式