JAVA设计模式之6种单例模式详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_16624353/article/details/81676240

单例会把默认的构造方法设为Private,让类自己来创建实例。。

第一种写法,饿汉式:

public class HungurySingleton { //缺点,无法延时加载,没有使用就已经加载了

    private static final HungurySingleton mInstance = new HungurySingleton();

    private HungurySingleton(){

    }

    public static HungurySingleton getHunguryInstance(){
        return mInstance;
    }

}

很明显,饿汉式在没有调用时就已经提前加载到了内存中,效率不是很高,无法实现延迟加载。。

第二种写法,懒汉式,优化了恶汉式无法延迟加载的问题

public class LazySingleton {//缺点,多线程并发的时候会失效,getmInstance不同步,例子:一个线程在创建mInstance时,还未创建完成,另一个线程访问mInstance此时还是为空,又创建了一次

    private static LazySingleton mInstance;

    private LazySingleton(){

    }

    public static LazySingleton getmInstance(){
        if(mInstance == null){
            mInstance = new LazySingleton();
        }
        return mInstance;
    }

}

懒汉式进行了延迟加载,在调用getmIntance方法时才会去判断mInstance是否为空,如果为空,再去进行实例的创建。。但是在多线程操作的时候,可能会创建多个mInstance实例,比如在以下情况下:一个线程在创建mInstance实例时,mInstance实例还未创建完成,但是另外一个线程会去访问mInstance发现此时mInstance还是为空,这个时候该线程又会去再次创建一个mInstance实例,最后会有多个mInstance实例被创建,导致资源的浪费。

第三种写法,懒汉式线程安全。。。

public class SafeLazySingleton { //性能有缺陷

    private static SafeLazySingleton mInstance;

    private SafeLazySingleton(){

    }

    public static synchronized SafeLazySingleton getmInstance() {//在方法中声明同步方法
        if(mInstance == null){
            mInstance = new SafeLazySingleton();
        }
        return mInstance;
    }
    
}

对懒汉式的优化,主要是在线程安全方面,有两种方式实现,上面第一种是使用synchronized关键字修饰,使得同时只能有一个线程访问

第二种是通过同步代码块来实现的

扫描二维码关注公众号,回复: 3009091 查看本文章
public class SafeLazySingleton { //性能有缺陷

    private static SafeLazySingleton mInstance;

    private SafeLazySingleton(){

    }

    public static SafeLazySingleton getmInstance(){ //同步代码块
        synchronized (SafeLazySingleton.class){
            if(mInstance == null){
                mInstance = new SafeLazySingleton();
            }
            return mInstance;
        }
    }
}

实际和第一种方式差不多,只是稍微有些不同通过同步代码块来控制多线程的访问和操作。

以上这两种方法都是存在性能缺陷的,因为使用了synchronized关键字。

第四种写法 DCL双重检查锁,是对第三种方法性能缺陷的优化

public class DLCSingleton {

    private static volatile DLCSingleton mInstance =null; //volatile关键字是为了禁止编译器对 volatile关键字修饰的变量进行重排序,并保证volatile变量的读操作发生在写操作之后

    private DLCSingleton(){

    }

    public static DLCSingleton getmInstance(){
        if(mInstance == null){ //第一次检查
            synchronized (DLCSingleton.class){ //同步代码块
                if(mInstance == null){ //第二次检查
                    mInstance = new DLCSingleton();
                }
            }
        }
        return mInstance;
    }

}

DCL双重检查锁仅在真正创建mInstance实例的时候加上了synchronized关键字。。。而且使用volatile关键字修饰,是为了禁止编译器对volatile变量重排序,并且保证volatile变量的读操作发生在写操作之后。。

第五种,静态内部类的实现方式。。

public class StaticInnerSingleton { //完成了懒汉式的延迟加载,同时static保证了线程安全。

    private  StaticInnerSingleton(){

    }

    public static StaticInnerSingleton getIntance(){
        return SingletonHolder.mIntance;
    }

    private static class SingletonHolder{ //私有的,初始化的时候,没有调用getIntance方法则不会加载
        private static final StaticInnerSingleton mIntance = new StaticInnerSingleton();  //static,final是jvm提供的同步机制,初始化后就无法修改了
    }

}

这种写法是最为推崇的写法,利用static final关键字的同步机制,初始化后就无法修改保证了线程安全。,使用holder的方式保证了延迟加载,不适用不会被加载。。。

第六种 枚举。枚举应该是think in java里面提到的,实际我发现没人这么用。很简洁,就几行代码

public enum  EnumSingleton { //1,写法简单,2,线程安全。枚举出现在java5以后
    INTANCE;
}

写法就两行,线程安全,枚举出现在JAVA5以后

猜你喜欢

转载自blog.csdn.net/qq_16624353/article/details/81676240
今日推荐