设计模式之单例模式

判官崔玨
• 阅读 896

单例模式

创建型模式

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

介绍

意图: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。

主要解决: 一个全局使用的类频繁地创建与销毁。

何时使用: 当您想控制实例数目,节省系统资源的时候。

如何解决: 判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

关键代码: 构造函数是私有的。


具体实现

1.饿汉式(静态变量)

public class SingletonTest01 {

    public static void main(String[] args) {
        Singleton singleton01 = Singleton.getInstance();
        Singleton singleton02 = Singleton.getInstance();
        System.out.println(singleton01 == singleton02); //true
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
    }

}

/**
 * 饿汉式(静态变量)
 */
class Singleton {
    //1.构造器私有化, 外部不能new
    private Singleton() {
    }

    //2.创建实例
    private final static Singleton instance = new Singleton();

    //3.提供一个公有的静态方法,返回实例对象
    public static Singleton getInstance() {
        return instance;
    }

}

优点:

这种写法比较简单,就是在类装载的时候就完成了实例化。避免了线程同步问题

缺点:

在类装载的时候就完成了实例化,没有达到Lazy Loading的效果。如果从始至终都没有使用过这个实例 , 则会造成内存的浪费。

总结:

这种单例模式可以使用 ,可能会造成内存浪费。

2.饿汉式(静态代码块)

public class SingletonTest02 {

    public static void main(String[] args) {
        Singleton singleton01 = Singleton.getInstance();
        Singleton singleton02 = Singleton.getInstance();
        System.out.println(singleton01 == singleton02); //true
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
    }

}

/**
 * 饿汉式(静态代码块)
 */
class Singleton {
    //1.构造器私有化,外部不能new
    private Singleton() {
    }

    //2.声明实例
    private final static Singleton instance;

    //3.创建实例
    static {
        instance = new Singleton();
    }

    //4.提供一个公有的静态方法,返回实例对象
    public static Singleton getInstance() {
        return instance;
    }

}

总结:

这种方式的优缺点和第一种类似,只不过将类的实例化过程放在了静态代码块中,依然可能造成内存浪费。

3.懒汉式(线程不安全)

public class SingletonTest03 {

    public static void main(String[] args) {
        Singleton singleton01 = Singleton.getInstance();
        Singleton singleton02 = Singleton.getInstance();
        System.out.println(singleton01 == singleton02); //true  (有可能为false)
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
    }

}

/**
 * 懒汉式(线程不安全)
 */
class Singleton {

    private Singleton() {
    }

    public static Singleton instance;

    //提供一个静态的公有方法,当使用到该方法时,才会创建instance
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点:

起到了Lozy Loading的效果,但是只能在单线程的环境下使用。

缺点:

如果在多线程环境下,大概率会产生多个实例。所以在多线程环境下不要使用这种方式。

总结:

实际开发中不要使用这种方式

4.懒汉式(线程安全)

public class SingletonTest04 {

    public static void main(String[] args) {
        Singleton singleton01 = Singleton.getInstance();
        Singleton singleton02 = Singleton.getInstance();
        System.out.println(singleton01 == singleton02); //true
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
    }
}

/**
 * 懒汉式(线程安全)
 */
class Singleton {

    private Singleton() {
    }

    public static Singleton instance;

    //提供一个静态的公有方法,当使用到该方法时,才会创建instance。
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点:

解决了线程不安全的问题。

缺点:

效率太低,因为是对整个方法加上了线程同步,其实只要在new的时候考虑线程同步就行了,这种方法不推荐使用。

总结:

在实际开发中 ,不推荐使用这种方式 。

5.懒汉式(双重检查锁)

public class SingletonTest05 {

    public static void main(String[] args) {
        Singleton singleton01 = Singleton.getInstance();
        Singleton singleton02 = Singleton.getInstance();
        System.out.println(singleton01 == singleton02); //true
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
    }

}

/**
 * 懒汉式(线程安全,双重检查锁)
 */
class Singleton {

    private Singleton() {
    }

    public static volatile Singleton instance;

    //提供一个静态的公有方法,加入双重检查代码,解决线程安全问题,同时解决懒加载问题
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

优点:

这种方式采用双锁机制,安全且在多线程情况下能保持高性能。

总结:

在实际开发中,推荐使用这种单例设计模式 。

6.静态内部类

public class SingletonTest06 {
    public static void main(String[] args) {
        Singleton singleton01 = Singleton.getInstance();
        Singleton singleton02 = Singleton.getInstance();
        System.out.println(singleton01 == singleton02); //true
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
        System.out.println("singleton01.hashCode = " + singleton01.hashCode()); //1625635731
    }

}

/**
 * 静态内部类
 */
class Singleton {

    private Singleton() {
    }

    //静态内部类中包含一个静态属性 Singleton
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }

}

优点:

  1. 这种方式能达到双检锁方式一样的功效,但实现更简单。
  2. 这种方式采用了类装载的机制来保证初始化实例时只有一个线程。
  3. 静态内部类的方式在Singleton类被装载的时候并不会立即初始化 , 而是在需要实例化时,调用getInstance方法才会装载SingletonInstance类,从而完成Singleton的实例化 。
  4. 类的静态属性只会在第一次加载类的时候进行初始化,所以这里JVM保证了线程安全性,在类进行初始化的时候 , 别的线程是无法进入的 。

总结:

避免了线程不安全,利用静态内部类的特点实现了延迟加载,效率高 ,推荐使用 。

7.枚举

public class SingletonTest07 {

    public static void main(String[] args) {
        Singleton instance1 = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance1 == instance2);
    }

}

/**
 * 枚举
 */
enum Singleton {
    INSTANCE;
}

优点:

这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法 。它更简洁,自动支持序列化机制,绝对防止多次实例化 。
这种方式是《 Effective Java 》作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题 ,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。

总结:

如果涉及到反序列化对象的时候可以采用采用这种方式,平常使用可以采用第五种。

点赞
收藏
评论区
推荐文章
3A网络 3A网络
3年前
Golang 常见设计模式之单例模式
之前我们已经看过了Golang常见设计模式中的装饰和选项模式,今天要看的是Golang设计模式里最简单的单例模式。单例模式的作用是确保无论对象被实例化多少次,全局都只有一个实例存在。根据这一特性,我们可以将其应用到全局唯一性配置、数据库连接对象、文件访问对象等。Go语言实现单例模式的方法有很多种,下面我们就一起来看一下。饿汉式饿汉式实现单例模式非
Wesley13 Wesley13
4年前
java设计模式1
1:单例模式简介  单例模式是一种常用的软件设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供唯一的实例。总而言之就是在系统中只会存在一个对象,其中的数据是共享的  特点:    单例类只能有一个实例,所以一般会用static进行修释。    单例类必须自己创建自己的唯一实例。也就是在类中要new一个自己。    单例类必
Wesley13 Wesley13
4年前
java 23种设计模式(五、单例模式)
作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。单例模式的结构  单例模式的特点:单例类只能有一个实例。单例类必须自己创建自己的唯一实例。单例类必须给所有其他对象提供这一实例。  饿汉式单例类publicclassEagerSingleton
红烧土豆泥 红烧土豆泥
4年前
创建型模式之单例设计模式
什么是单例设计模式?顾名思义,只有一个实例。单例模式它主要是确保一个类只有一个实例,并且可以提供一个全局的访问点。废话少说,直接上干货了单例模式之饿汉式所谓饿汉式,顾名思义,“它很饿”。所以说,它一旦被加载进来,就会直接实例化一个对象。例如:languageclassSingleton{privatestaticfin
Wesley13 Wesley13
4年前
JAVA设计模式之单例设计模式
    单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。  在JAVA中实现单例,必须了解JAVA内存机制,JAVA中实例对象存在于堆内存中,若要实现单例,必须满足两个条件:  1.限制类实例化对象。即只能产生一个对象。
Wesley13 Wesley13
4年前
Java单例模式
什么是单例模式  单例模式是在程序中,一个类保证只有一个实例,并提供统一的访问入口。为什么要用单例模式节省内存节省计算如对象实例中的一样的,那就不用每次都创建一个对象方便管理因为单例提供一个统一的访问入口,不需要创建N多个对象,很多工具类都用了单例实现,如日志、字符串工具类
Wesley13 Wesley13
4年前
PHP单例模式(精讲)
首先我们要明确单例模式这个概念,那么什么是单例模式呢?单例模式顾名思义,就是只有一个实例。作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类我们称之为单例类。单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例
Stella981 Stella981
4年前
C#设计模式(1)——单例模式(Singleton)
单例模式即所谓的一个类只能有一个实例,也就是类只能在内部实例一次,然后提供这一实例,外部无法对此类实例化。单例模式的特点:1、只能有一个实例;2、只能自己创建自己的唯一实例;3、必须给所有其他的对象提供这一实例。普通单例模式(没有考虑线程安全)  ///<summary///单例模式
Wesley13 Wesley13
4年前
(面试常问)4种单例设计模式的总结(内含代码以及分析)
单例设计模式:  单例模式,是一种常见的软件设计模式.在它的核心结构中只包含了一个被称为单例的特殊类.通过单例模式可以保证系统中只有该类的一个实例对象.优点:  实例控制:单例模式会阻止其它对象实例化其自己的单例对象的副本,从而确保所有对象都访问的是唯一的实例   灵活性:因为类控制了实例化过程,所以类可以很灵活的更改实
Wesley13 Wesley13
4年前
Java设计模式:Singleton(单例)模式
概念定义Singleton(单例)模式是指在程序运行期间,某些类只实例化一次,创建一个全局唯一对象。因此,单例类只能有一个实例,且必须自己创建自己的这个唯一实例,并对外提供访问该实例的方式。单例模式主要是为了避免创建多个实例造成的资源浪费,以及多个实例多次调用容易导致结果出现不一致等问题。例如,一个系统只能有一个窗口管理器或文件系统,一个程
Wesley13 Wesley13
4年前
23种设计模式(1):单例模式
定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。类型:创建类模式类图:!23种设计模式(1):单例模式第1张|快课网(http://static.oschina.net/uploads/img/201407/05200605_0dij.gif"23种设计模式(1):单例模式
判官崔玨
判官崔玨
Lv1
明明都无言以对,还要硬聊,这就是喜欢
文章
2
粉丝
0
获赞
0