欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

单例模式的实现

程序员文章站 2022-07-13 23:37:58
...

两种模式

  • 饿汉模式

饿汉模式:加载类时比较慢,运行时获取对象的速度快,线程安全

  • 懒汉模式

懒汉模式:加载类时比较快,运行时获取对象的速度慢,线程不安全

实现思路

单例模式要求类能够返回对象一个引用(永远是同一个)和一个获取该实例的方法(必须是静态方法)

实现步骤

1.将构造方法私有化,不允许外界直接创建对象
2.声明唯一的实例,使用private static修饰
3.提供一个public static 修饰的获取实例的方法

注意事项

懒汉模式是线程不安全的,当唯一实例未创建时,同时有两个线程调用创建方法,又同时检测到没有唯一实例,而各自创建了一个实例,这时就有两个实例构造出来了,违反了单例模式唯一的原则。让我们接着往下看,有什么解决方法

静态模式的八种写法

1.饿汉模式(静态常量)【可用】

public class Singleton{
  // 将构造方法私有化,不允许外界直接创建对象
  private Singleton(){}
 // 声明唯一实例
  private final static Singleton instance = new Singleton();
  // 提供一个获取实例的方法
  public static Singleton getInstance(){
    return instance;
  }
}
优点:写法简单,在类加载的时候就完成实例化,避免线程同步问题
缺点:在类加载的时候完成实例的创建,没有达到Lazy Loading的效果。如果没有用过这个实例,会造成内存浪费

2.饿汉模式(静态代码块)【可用】

public class Singeton{
    private static Singleton instance;
    static{
      instance = new Singleton();
    }
    private Singleton(){}
    public static Singleton getInstance() {
        return instance;
    }
}
优点:同上,不过将类实例化的过程放在静态代码块中,在类加载的时候,执行静态代码块里面的代码,初始化类实例
缺点:同上

3.懒汉模式(线程不安全)【不可用】

public class Singeton{
    private static Singleton instance;
    private Singleton(){}
    public static Singleton getInstance() {
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }
}
优点:起到Lazy Loading效果
缺点:只能在单线程时使用,可能同时两个线程进入判读语句,产生多个实例

4.懒汉模式(线程安全,同步方法)【不可用】

public class Singeton{
    private static Singleton instance;
    private Singleton(){}
    public static synchronized Singleton getInstance() {
        if(singleton == null){
            singleton = new Singleton();
        }
        return instance;
    }
}
优点:解决了上面线程不安全的问题,对getInstance()方法进行了线程同步
缺点:效率太低,每个线程想获取类的实例时,执行getInstance()方法都要进行同步,其实只有第一次对象未实例化时需要同步,以后直接return就可以了

5.懒汉模式(线程安全,同步代码块)【不可用】

public class Singeton{
    private static Singleton instance;
    private Singleton(){}
    public static  Singleton getInstance() {
        if(singleton == null){
            synchronized (Singleton.class){
              singleton = new Singleton();
            }
        }
        return instance;
    }
}
改进了上一个方法,采用同步代码块,但是并不能起到线程同步的作用,如果同时两个线程进入判读,虽然实例化的部分加上了锁,同时只有一个线程可以实例化,但是待第一个线程释放了锁,第二个线程也会实例化一次(已经进入了判读),产生多个实例

6.懒汉模式(双重检查 )【推荐用】

public class Singeton{
    private static volatile Singleton instance;
    private Singleton(){}
    public static  Singleton getInstance() {
        if(singleton == null){
            synchronized (Singleton.class){
              if(singleton == null){
                  singleton = new Singleton();
              }
            }
        }
        return instance;
    }
}
Double-Check,保证线程安全,实例化的代码也只会执行一次。线程安全,Lazy Loading,效率高。

7.似饿汉模式(静态内部类)【推荐用】

public class Singeton{
    private Singleton(){}

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

和懒汉模式类似,但有所区别,两者都采用了类装载的机制,保证初始化实例的只有一个线程,不同的地方在于,饿汉模式只要Singleton类被装载就会实例化,没有Lazy Loading,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化的地方,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。类的静态属性只会在第一次加载类的时候初始化,所以JVM保证了线程的安全

优点:线程安全,Lazy-Loading,效率高

7.枚举【推荐用】

public enum Singeton{
    INSTANCE;
    public void anyMethod() {
    }
}

借助JDK1.5添加的枚举类实现单例模式。不仅避免了多线程同步问题,还能反正反序列化重新创建新的对象。卵秀飞

优点:真的秀

单例模式的优点

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

单例模式的缺点

当想实例化一个单例类的时候,必须记住使用相应的获取对象的方法,而不是直接new,可能给其它开发人员造成困扰

单例模式适用场景

  • 需要频繁创建销毁的对象
  • 创建很耗资源,当使用频繁
  • 工具类对象
  • 频繁访问数据库或文件的对象
为什么实例必须为静态,获取实例的方法也必须为静态?

你只要弄明白单例模式是如何实现的,就能从本质上理解这个问题;
单例模式实现过程如下:
首先,将该类的构造函数私有化(目的是禁止其他程序创建该类的对象);
其次,在本类中自定义一个对象(既然禁止其他程序创建该类的对象,就要自己创建一个供程序使用,否则类就没法用,更不是单例);
最后,提供一个可访问类自定义对象的类成员方法(对外提供该对象的访问方式)。

直白的讲就是,你不能用该类在其他地方创建对象,而是通过该类自身提供的方法访问类中的那个自定义对象。

那么问题的关键来了,程序调用类中方法只有两种方式,①创建类的一个对象,用该对象去调用类中方法;②使用类名直接调用类中方法,格式“类名.方法名()”;
上面说了,构造函数私有化后第一种情况就不能用,只能使用第二种方法。
而使用类名直接调用类中方法,类中方法必须是静态的,而静态方法不能访问非静态成员变量,因此类自定义的实例变量也必须是静态的。
这就是单例模式唯一实例必须设置为静态的原因。

参考地址:

+https://www.cnblogs.com/zhaoyan001/p/6365064.html

转载于:https://www.jianshu.com/p/63a010d94a39