单例模式

总结常见的单例模式

1.单例模式概述

  单个例子模式定义应该是这样的:一个类在被使用的时候只能有一个实例化对象,这种模式就称为单例模式。概念不难,实现这个模式有相应的套路,前人已经为我们总结出了经验。大致思路是这样的:为了在使用这个类时不产生多个对象,首先构造方法要私有,第二,构造一个静态方法产生这个单个实例。基于这两点思想,同时考虑多线程情况下使用这个类也只生成一个对象,总结出以下4种写法。

2.单例分类

  单例模式的实现有两种类型,饿汉式和懒汉式。

饿汉式:

/**
 * 单例模式(饿汉式)
 */
class Singleton{
    public static final Singleton instance = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return instance;
    }
}

  这是最简单的一种单例模式,称为饿汉式,在Singleton类加载时,instance对象就初始化了,而在外部只能通过调用getInstance静态方法得到这个唯一的对象,因为构造方法私有了,无法new一个对象。不管是否调用getInstance方法,在类加载过程中都创建好了实例,同时也避免了多线程下调用getInstanc方法而产生的线程安全问题,缺点是无论是否调用getInstance方法,对象都已创建,这样会占用一定的内存空间。由于这种方法比较粗暴,所以称为饿汉式。

懒汉式

  为了保证线程安全,这里介绍三种方式

第一种(常规方式)
/**
 * 单例模式(懒汉式)
 */
class Singleton{
    public static Singleton instance = null;
    private Singleton(){}
    public static synchronized Singleton getInstance(){
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

  这种方法在类加载时并不会初始化对象,而是在调用getInstance方法时才会初始化对象,getInstance方法使用synchronized关键字修饰可以解决线程安全问题。缺点是每次调用都会进行同步,这样对性能是有影响的。

第二种(双重校验方式)
/**
 * 单例模式(双重校验模式)
 */
class Singleton{
    public static Singleton instance = null;
    private Singleton(){}
    public static Singleton getInstance(){
        if (instance == null){
            synchronized (Singleton.class){
                if (instance == null){
                    instance = new Singleton();
                }
            }

        }
        return instance;
    }
}

  相较于常规方式,这种方式只在第一次实例化对象的时候需要同步,之后就不需要,这样节省性能,由于同步机制,所以要进行两次判断,所以叫双重验证方式

第三种(静态内部类方式)
/**
 * 单例模式(静态内部类方式)
 */
class Singleton {
    private Singleton() {}
    public static class SingletonHoder {
        public static final Singleton instance = new Singleton();
    }
    public static Singleton getInstance(){
        return SingletonHoder.instance;
    }
}

  这是一种非常巧妙的方式,利用了静态内部类实现。这种方式利用了classloder的机制来保证初始化instance时只有一个线程,而不是只要Singleton类被装载了instance就会被实例化(没有达到lazy loading效果),Singleton类被装载了,instance不一定被初始化,因为SingletonHolder类没有被主动使用,只有显式通过调用getInstance方法时,才会显式装载SingletonHolder类,从而实例化instance。在某些情况下,如果实例化instance很消耗资源,我想让他延迟加载,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这种方式也没有使用同步,但保证了线程安全,所以相比前两种要更就显得合理一些。

3.总结

还有一种更好的方式,是《Effective Java》推荐的,就是枚举方式,这个以后再做总结。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值