单例模式

 

单例模式

定义:某个类仅有一个唯一的实例,并且提供一个全局的访问点来访问这一实例。

注意

  1.该类只能有一个实例

  2.必须是自己创建的这一个唯一的实例

  3.必须自己向整个系统提供这个实例

代码实现

  1.目的是一个类只有一个实例,并且提供全局的访问点

  2.包含的角色只有一个

  3.构造函数是私有的,无法通过new对象的方式创建实例

  4.有一个静态的私有成员变量和静态的共有的工厂方法

注意

  1.单例类构造器的可见行为private

  2.提供一个类型为自身的静态私有成员变量

  3.提供共有的静态工厂方法

优点:

  1.严格控制客户程序访问其唯一的实例。

  2.单例类可以自带一些子类,它的每个子类都是单例类。

  3.该模式的类可以比较容易允许创建一定数目的对象类。

缺点

  1.单例模式,没有抽象层,扩展比较困难

  2.在一定程度上违背了单一职责原则

  3.容易导致单例状态丢失,系统存在垃圾回收机制,长时间不使用,会被系统自动回收,再次使用就需要再次实例

 、

实现:

1.创建一个Singleton类

public class Singleton {
    //私有构造器
    private  Singleton(){}

    //私有的Singleton对象
    private static  Singleton instance = new Singleton();

    public static Singleton getInstance(){
        return instance;
    }

    public void  Say(){
        System.out.println("Hello Singleton");
    }
}

 2.创建TestSingleton类:

在类里使用new 的方法是会报错的

public class TestSingleton {
    public static void main(String[] args) {

        Singleton singleton = Singleton.getInstance();

        singleton.Say();
    }
}

3.运行结果是

Hello Singleton

 单例模式的其他实现方式:

1.懒汉式,线程不安全

是否 Lazy 初始化:

是否多线程安全:

实现难度:

描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。

public class Singleton {
   
    private static  Singleton instance;

    private Singleton(){};

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

2.懒汉式,线程安全

是否 Lazy 初始化:

是否多线程安全:

实现难度:

描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。

public class Singleton {
    //懒汉式
    private static  Singleton instance;

    private Singleton(){};

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

3.饿汉式

是否 Lazy 初始化:

是否多线程安全:

实现难度:

描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。

public class Singleton {
    
    private  Singleton(){}

    private static  Singleton instance = new Singleton();

    public static Singleton getInstance(){
        return instance;
    }
}

4.双检锁/双重校验锁

JDK 版本:JDK1.5 起

是否 Lazy 初始化:

是否多线程安全:

实现难度:较复杂

描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
getInstance() 的性能对应用程序很关键。

public class Singleton {

    private volatile static Singleton instance;

    private Singleton(){}

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

5.登记式/静态内部类

是否 Lazy 初始化:

是否多线程安全:

实现难度:一般

描述:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。

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

备注:

代码部分的实现以及部分讲解来源于:http://www.runoob.com/design-pattern/singleton-pattern.html

原文地址:https://www.cnblogs.com/Mrchengs/p/9801530.html