Java设计模式之几种常见的单例模式的写法及优缺点比较

概述

今天再来总结一篇开发中常用的设计模式单例模式,其定义是单例对象的类只能允许一个实例存在,它虽然有多种常见的写法,但是其基本思想不变:

  1. 构造器私有化,使外部无法无法new 对象
  2. 提供一个获取对象的方法 即提供一个get方法获取第三部中的属性,但是要求所有对象共用故而用static修饰
  3. 内部提供一个实例 作为属性 要求私有化 静态化 private static

单例模式几种常见的写法

1:饿汉模式

  1. 优点:写法比较简单、线程安全,在类加载的时候就完成实例化。
  2. 缺点:在类加载的时候就完成实例化,没有达到Lazy Loading(懒加载)的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。
public class SingleInstance {
    //饿汉模式线程安全
    //step1 :私有化构造器
    private SingleInstance() {
    }
    //step2 :提供私有化静态属性
    private static SingleInstance sSingleInstance = new SingleInstance();
    //step3 : 通过获取该属性的方法
    public static SingleInstance getInstance() {
        return sSingleInstance;
    }
}

2:懒汉模式

  1. 优点:这种方式实现了Lazy Loading的效果,单线程提可保证单例
  2. 缺点:线程不安全,只适用于单线程不适用于多线程
public class SingleInstance {
    //懒汉模式
    //step1 :私有化构造器
    private SingleInstance(){}
    //step2 :提供私有化静态属性
    private static SingleInstance sInstance;
    //step3 : 通过获取该属性的方法
    public static SingleInstance getInstance(){
        if (sInstance == null) {
            sInstance=new SingleInstance();
        }
        return sInstance;
    }
}

3:懒汉模式:同步方法

通过synchronized 修饰该方法,保证线程安全

  1. 优点:实现了懒加载,并且线程安全
  2. 缺点:效率低不推荐使用,因为使用了synchronized修饰方法,每次使用时都得同步
public class SingleInstance {
    //懒汉模式 同步方法
    //step1 :私有化构造器
    private SingleInstance(){}
    //step2 :提供私有化静态属性
    private static  SingleInstance sInstance;
    //step3 : 通过获取该属性的方法  synchronized修饰该方法
    public static synchronized SingleInstance getInstance(){
        if (sInstance == null) {
            sInstance=new SingleInstance();
        }
        return sInstance;
    }
}

4:懒汉模式:同步代码块

通过synchronized 修饰该方法,保证线程安全

  1. 优点:实现了懒加载,
  2. 缺点:线程不安全,和方法二一样不适用于多线程,不推荐使用

public class SingleInstance {
    //懒汉模式  同步代码快
    //step1 :私有化构造器
    private SingleInstance(){}
    //step2 :提供私有化静态属性
    private static  SingleInstance sInstance;
    //step3 : 通过获取该属性的方法  synchronized修饰该方法
    public static  SingleInstance getInstance(){
        if (sInstance == null) {
            synchronized (SingleInstance.class){
                sInstance=new SingleInstance();
            }
        }
        return sInstance;
    }
}

5:双重锁机制(推荐)

优点:实现了懒加载,线程安全,效率高,第一层判null提高了锁机制的使用效率,第二层判null才是真正意义的单例。

public class SingleInstance {
    //双重锁
    //step1 :私有化构造器
    private SingleInstance(){}
    //step2 :提供私有化静态属性
    private static  SingleInstance sInstance;
    //step3 : 通过获取该属性的方法  synchronized修饰该方法
    public static  SingleInstance getInstance(){
        if (sInstance == null) {//第一层:保证的多线程只有第一次调用getInstance 的时候才会加锁初始化
            synchronized (SingleInstance.class){
                if (sInstance==null) {// 第二层 实现了单例模式
                    sInstance=new SingleInstance();
                }
            }
        }
        return sInstance;
    }

6:静态内部类(推荐)

优点:避免了线程不安全,延迟加载,效率高。

public class SingleInstance {
    //静态内部类
    //step1 :私有化构造器
    private SingleInstance(){}
    //step2 :提供私有化静态属性
    private static  SingleInstance sInstance;
    //step3 : 通过获取该属性的方法  synchronized修饰该方法
    public static  SingleInstance getInstance(){
        //只有调用此方法的时候才会初始化单例,实现了懒加载,因为类(Single)的加载只有一次,从而保证了单例
        return Single.sInstance;
    }

    private static class Single{
        private static SingleInstance sInstance=new SingleInstance();

    }
}

这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。

类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

单例模式的优缺点以及使用场景

优点: 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。

优点:
系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。

缺点:
单例类的职责过重,在一定程度上违背了“单一职责原则”。

适用场景:

  1. 工具类对象;
  2. 需要频繁的进行创建和销毁的对象,并且创建对象时耗时过多或耗费资源过多,如:访问I0和数据库等资源或者有很多个地方都用到了这个实例。
  3. 频繁访问数据库或文件的对象,

猜你喜欢

转载自blog.csdn.net/weixin_37639900/article/details/90142326