单例模式

单例模式是经常用到的一种设计模式,因为很多时候,我们完全可以重复使用一个实例,而没必要每次都去创建这个实例,这样可以很大程序减少开销。这个时候,单例模式就应用而生了。

单例的实现其实很简单,只要遵循两步可以:

  1. 把自己的构造方法私有化。
  2. 暴露一个static静态方法。

具体代码如下:

public class SingleInstance {
    private static SingleInstance instance;

    private SingleInstance() {

    }

    private static SingleInstance getInstance() {
        if (instance == null) {
            instance = new SingleInstance();
        }
        return instance;
    }
}

这种方式是单例中最简单的写法,也俗称“懒汉模式”,就是仅仅按原理去实现了,并没有考虑太多的其它问题(比如并发引起的线程安全问题)。试想,假如有两个线程,A线程需要这个实例,进到getInstance方法,判断为空,所以会进行初始化对象操作,但正在初始化的时候,B线程也进来了,但对象还没初始化完,这时候也为空,所以B也会进行初始化操作,这样就会初始化两个对象。
如果想避免这种方式,我们首先想到的方式,就是使用synchronized关键字。

private static synchronized SingleInstance getInstance() {
        if (instance == null) {
            instance = new SingleInstance();
        }
        return instance;
}

加上synchronized关键字,这个时候如果A线程正在获取这个实例,B线程也想获取这个实例的时候,就会阻塞,这样基本就解决这个问题了。为什么说“基本”呢,因为这还属于“懒汉”式的解决问题,只是为了解决问题,而没有考虑到特殊性。比如,线程进来都会先阻塞,然后取实例,这样效率大大下降了。所以可以再进行以下方式优化。

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

这种方式,称之为“双重验证方式”,首先判断实例为不为空,如果不为空,直接就返回实例,也不会阻塞线程。如果实例为空的时候,基本上就是第一次使用,或者被系统销毁后,才会阻塞线程,去创建实例。但是为什么还有第二次判断为空呢?是因为如果实例为空,A线程创建完成,释放掉锁后,B线程拿到锁后,可能又会去创建线程,所以会再次判断。

当然还有一种方式可以解决线程安全的问题,那就是一开始先把实例给初始化好,然后通过静态方法把实例对象暴露出来。
代码如下:

public class SingleInstance {
    private static SingleInstance instance = new SingleInstance();

    private SingleInstance() {

    }

    private static SingleInstance getInstance() {
        return instance;
    }
}

这种方式,大家也称之为“饿汉模式”,因为只要娄一加载,不管需要不需要,先把对象初始化,然后直接返回对象,而切如果初始化的时候,需要依赖一些参数,那么这种方式就无法使用了。

所以综上所述,最好的方式,是双重验证方式。即能保证需要的时候,才会初始化,又能保证线程的安全。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值