【设计模式】单例(Singleton)

设计模式–单例模式(Singleton)

确保一个类只有一个实例,并提供该实例的全局访问点。

1、懒汉式–线程不安全

私有静态变量 instance 被延迟加载,只在第一次用到时进行实例化,若没有用到该类,就不会进行实例化,从而节约资源。
该方式在多线程环境下是线程不安全的,如果多个线程同时进入if (instance == null),并且此时
instance 为 null, 将会使 instance 实例化多次

public class Singleton {

    private static Singleton instance;

    private Singleton(){}

    public static Singleton getInstance(){
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

2、饿汉式–线程安全

不管该类有没有用到,采取直接实例化的方式,这样也不会有线程安全问题。但丢失了延迟实例化带来的节约资源的好处

public class Singleton {

    private static Singleton instance = new Singleton();

    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
}

3、懒汉式–线程安全

只要对 getInstance() 方法加锁,那么在一个时间点只能有一个线程能够进入该方法,从而避免多次实例化

但是当一个线程进入该方法后,其他试图进入该方法的线程不管 instance有没有被实例化,都必须等待。将使线程阻塞时间过长,因此存在性能问题。

public class Singleton {

    private static Singleton instance;

    private Singleton(){}

    public static synchronized Singleton getInstance(){
        
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

4、双重校验锁–线程安全

instance只要被实例化一次,之后就可以直接使用了。因此加锁操作只需对实例化代码部分进行。双重校验先判断 instance是否已经实例化, 没有实例化在对实例化操作加锁。

public class Singleton {

    private volatile static Singleton instance;

    private Singleton(){}

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

为何要用两个 if 语句进行判断?

考虑当只有一个 if 的时候,在 instance == null的情况下,当多个线程都来执行时,虽然有加锁操作,但最终多个线程都会去执行加锁代码块中的内容,又将导致 instance实例化多次。因此必须使用双重 if 判断。

为何要使用 volatile 关键字修饰 instance?

对象实例化时分为三步执行:
1、为 instance 分配内存空间
2、初始化 instance
3、将 instance 指向分配的内存地址
由于JVM具有指令重排的特性,以上三步执行顺序可能发生改变。当线程1执行了 1、3步骤之后,线程2执行了方法 getInstance()发现 instance不为空,直接返回了 instance。但此时 instance 还未被初始化。使用 volatile可以禁止JVM的指令重排,保证多线程下也能正常执行。

5、静态内部类实现

6、枚举实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值