设计模式之单例模式

什么是单例模式?

在我们生活中,有很多对象是只能存在的一个的,比如,世界上只有一个太阳,一个国家只能有一个正的主席(总统),一个公司只有一个正的董事长、CEO。这些都是单例模式在我们生活中的体现。单例模式让我们的这个对从头到尾都是同一个,保证了属性不变,这样可以节约资源,不用花费多余的空间去新建对象。

单例模式的特性

1、单例类只能有一个实例。

2、单例类必须自己创建自己的唯一实例。

3、单例类必须给所有其他对象提供这一实例。

单例模式的实现形式有很多种,下面我们一个一个的介绍!

懒汉式,线程不安全 

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

懒汉式,线程安全

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

对比上面的两个单例模式的写法,后面一个相对于前面加了一个同步,保证了在同一时刻,只有一个线程能够访问这个程序,保证了线程的安全。但是上面这个虽然保证了线程的安全,解决了多个实例的问题,但是它的效率并不高。因为在任何时候只能有一个线程调用getInstance()方法。但是同步只需要第一次调用时才被需要,即第一次创建单例对象时。这就引出了双重检验锁。

双重检验锁,线程安全

public class Singleton {
    private volatile static Singleton instance;
    private Singleton (){}
    public static Singleton getInstance() {
     if (instance == null) {                //Single Checked
         synchronized (Singleton.class){
             if(instance == null){         //Double Checked
                 instance = new Singleton();
             }
         }
     }
     return instance;
    }
}

双重锁保证了当多个线程进入同步块外的if,经过二次检测,保证最后只有一个线程进入内部。第一句加的volatile保证各原子性,因为在执行 instance= new Singleton()这句时,JVM做了一下三件事:

1、给instance分配内存;

2、调用Singleton的构造函数来初始化成员变量;

3、将instance对象指向分配的内存空间(执行完这一步instance就不是NULL了)

但是在JVM即时编译器中存在指令重排序的优化。也就是不能保证一定按123顺序来执行,造成程序的错误,所以加上关键词volatile来保证原子性。

 饿汉式

public class Singleton{
    //类加载时就初始化
    private static final Singleton instance = new Singleton();  
    private Singleton(){}
    public static Singleton getInstance(){
        return instance;
    }
}

这种方法简单粗暴,犹如名字,在刚开始的时候我就把你初始化,即使你还没有调用getInstance()方法;这样导致它在某些场合是无法使用的,比如说创建实例需要依赖参数或者配置文件,那就无法使用了。

静态内部类

public class Singleton {  
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE; 
    }  
}

这种写法仍然使用JVM本身机制保证了线程安全问题;由于SingletonHolder 是私有的,除了 getInstance() 之外没有办法访问它,因此它是懒汉式的;同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖 JDK 版本。

枚举

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
        } 
 }  

这种方法我第一眼看到就喜欢上了,面试的时候,写出这玩意儿太容易了!它自动支持序列化机制,绝对防止多次实例化。

参考博客:

http://wuchong.me/blog/2014/08/28/how-to-correctly-write-singleton-pattern/

http://www.runoob.com/design-pattern/singleton-pattern.html

 











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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值