重修设计模式-单例模式

重修设计模式-单例模式:

0.修前叨叨:

设计模式,一共23个.从今天开始,我打算每天抽空重修一个,方便自己的记忆以及更深入的理解.
单例模式算是接触比较多的一个东西.以前,用的比较多.对于这个东西,起初觉得比较简单,只是对于重量级实例的封装容器的方式.现在,回头再来看,发现细节远不止这些.

1.概念:

单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。

2.深挖细节:

单例模式,会在多种场景下使用,所需的实现方式和要求也各不相同.

2.1饿汉法:

public class Singleton {   
    private static Singleton = new Singleton();
    private Singleton() {}
    public static getSignleton(){
        return singleton;
    }
}

故名思议,一看就是没吃饱.所以,在jvm启动的时候通过在class初始化的连接过程中进行赋值.其他调用的地方就可以放心使用,完全不用害怕线程的影响啦.但是,这个方式如果遇到需要延迟加载的类,那就不太合适了.这种需要延迟加载的单例,就需要下面的懒汉来处理.

2.2懒汉法:

2.2.1线程不安全:

public class Singleton {
    private static Singleton singleton = null;
    private Singleton(){}
    public static Singleton getSingleton() {
        if(singleton == null) {//check&pro 明显的线程不安全点
                singleton = new Singleton();
        }
        return singleton;
    }
}

上面的代码,在单线程使用的情况下是没有任何问题的.但是,被多线程使用的话,这个singleton对象会有被多次初始化的风险.因为,我们使用懒汉式的单例模式必然是有一个类加载比较消耗资源,我们连开机的时候都不想加载他.当被多次初始化的话,会对程序的性能产生很大的影响.

2.2.2线程安全:

public class Singleton {
    private static Singleton singleton = null;
    private Singleton() {
    }

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

咯,上面的代码里面加了个synchronized关键字,将本对象锁住以后就可以在判断的时候避免发生脏数据干扰,同时,由于单例模式的对象初始化一般都比较耗时,这时如果有其他线程也来获取的话可以阻塞住,直到单例创建完成以后再返回对象.但是,这也产生了新的问题,就是多线程跑到这里都变成了单线程了.接下来我们就会介绍一种兼顾线程安全和性能的实现思路

2.2.3线程安全和性能兼顾的:

public class Singleton {
    private static volatile Singleton singleton = null;
 
    private Singleton(){}
 
    public static Singleton getSingleton(){
        if(singleton == null){
            synchronized (Singleton.class){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }    
}

上述代码,会在多线程获取单例时先判断是否有对象,如果有就不会去同步直接返回.如果没有就会去走同步check和处理.这样的处理方式兼顾了线程安全和单例实例生成后的多线程性能.但是,整个对象是存在的判断是基于volatile这个关键字的可见性和不可变性.经过查询的资料,volatile的代码不可变性实际上是在jdk1.5以后才真正的实现的,所以这个写法在jdk1.5及其以下的版本中使用是线程不安全的.

2.3静态内部类&枚举法

由于这2种方法具体的原理我不太熟悉,后面在更加深入了解原理后再补全.

你可能感兴趣的:(重修设计模式-单例模式)