java编程创建型设计模式单例模式的七种示例

目录
  • 1.什么是单例模式?
  • 2.七种写法
    • 2.1饿汉式(静态常量)
    • 2.2饿汉式(静态代码块)
    • 2.3懒汉式(线程不安全)
    • 2.4懒汉式(线程安全,同步方法)
    • 2.5双重校验锁
    • 2.6静态内部类
    • 2.7枚举
  • 3.单例模式在JDK中的应用(简单的源码分析)
  • 4.单例模式总结

1.什么是单例模式?

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。

比如Hibernate的 SessionFactory,它充当数据存储源的代理,并负责创建Session对象。SessionFactory并不是轻量级的,一般情况下,一个项目通常只需要一个SessionFactory就够,这是就会使用到单例模式。

这篇文章中,我将给出单例模式的七种写法:

  • 饿汉式(静态常量)
  • 饿汉式(静态代码块)
  • 懒汉式(线程不安全)
  • 懒汉式(线程安全,同步方法)
  • 双重校验锁
  • 静态内部类
  • 枚举

以上七种写法中标红的是推荐使用的,如果说你能保证你的程序中单例类的实例一定会使用到,那么饿汉式也是推荐使用的。

2.七种写法

2.1 饿汉式(静态常量)

package com.szh.singleton.type1;
/**
 * 饿汉式(静态变量)
 */
class Singleton {
    // 本类内部创建对象实例
    private static final Singleton INSTANCE = new Singleton();
    // 构造方法私有化, 防止外部new对象
    private Singleton() {}
    // 提供一个公有的静态方法,返回实例对象
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
public class SingletonTest01 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);
        System.out.println("singleton1的hashCode = " + singleton1.hashCode());
        System.out.println("singleton2的hashCode = " + singleton2.hashCode());
    }
}

优缺点说明:

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

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

这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,在单例模式中大多数都是调用getInstance方法,但是导致类装载的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance就没有达到lazy loading 的效果。

结论:这种单例模式可用,可能造成内存浪费。

2.2 饿汉式(静态代码块)

package com.szh.singleton.type2;
/**
 * 饿汉式(静态代码块)
 */
class Singleton {
    private static final Singleton INSTANCE;
    // 构造方法私有化, 防止外部new对象
    private Singleton() {}
    // 静态代码块, 完成对象的实例创建
    static {
        INSTANCE = new Singleton();
    }
    // 提供一个公有的静态方法,返回实例对象
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
public class SingletonTest02 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);
        System.out.println("singleton1的hashCode = " + singleton1.hashCode());
        System.out.println("singleton2的hashCode = " + singleton2.hashCode());
    }
}

优缺点说明:

这种方式和第一种方式其实类似,只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例。优缺点和上面是一样的。

结论:这种单例模式可用,但是可能造成内存浪费。

2.3 懒汉式(线程不安全)

package com.szh.singleton.type3;
import java.util.Objects;

/**
 * 懒汉式(线程不安全)
 */
class Singleton {
    private static Singleton instance;
    // 构造方法私有化, 防止外部new对象
    private Singleton() {}
    // 提供一个公有的静态方法,返回实例对象
    public static Singleton getInstance() {
        if (Objects.isNull(instance)) {
            instance = new Singleton();
        }
        return instance;
    }
}
public class SingletonTest03 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);
        System.out.println("singleton1的hashCode = " + singleton1.hashCode());
        System.out.println("singleton2的hashCode = " + singleton2.hashCode());
    }
}

优缺点说明:

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

如果在多线程下,一个线程进入了if (singleton== null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。

结论:  在实际开发中,不要使用这种方式。

2.4 懒汉式(线程安全,同步方法)

package com.szh.singleton.type4;
import java.util.Objects;
/**
 * 懒汉式(线程安全, 双重校验锁)
 */
class Singleton {
    private static Singleton instance;
    // 构造方法私有化, 防止外部new对象
    private Singleton() {}
    // 提供一个公有的静态方法,返回实例对象
    public static synchronized Singleton getInstance() {
        if (Objects.isNull(instance)) {
            instance = new Singleton();
        }
        return instance;
    }
}
public class SingletonTest04 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);
        System.out.println("singleton1的hashCode = " + singleton1.hashCode());
        System.out.println("singleton2的hashCode = " + singleton2.hashCode());
    }
}

优缺点说明:

解决了线程安全问题。

效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。方法进行同步效率太低。

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

2.5 双重校验锁

package com.szh.singleton.type5;
import java.util.Objects;
/**
 * 懒汉式(线程安全)
 */
class Singleton {
    private static volatile Singleton instance;
    // 构造方法私有化, 防止外部new对象
    private Singleton() {}
    // 提供一个公有的静态方法,返回实例对象
    public static Singleton getInstance() {
        if (Objects.isNull(instance)) {
            synchronized (Singleton.class) {
                if (Objects.isNull(instance)) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
public class SingletonTest05 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);
        System.out.println("singleton1的hashCode = " + singleton1.hashCode());
        System.out.println("singleton2的hashCode = " + singleton2.hashCode());
    }
}

优缺点说明:

Double-Check概念是多线程开发中常使用到的,如代码中所示,我们进行了两次if (singleton ==- null)检查,这样就可以保证线程安全了。

这样,实例化代码只用执行一次,后面再次访问时,判断if(singleton == null),直接return 实例化对象,也避免的反复进行方法同步。

线程安全;延迟加载;效率较高。

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

2.6 静态内部类

package com.szh.singleton.type6;
import java.util.Objects;
/**
 * 静态内部类
 */
class Singleton {
    // 构造方法私有化, 防止外部new对象
    private Singleton() {}
    // 定义静态内部类
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }
    // 提供一个公有的静态方法,返回静态内部类中的实例对象
    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}
public class SingletonTest06 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);
        System.out.println("singleton1的hashCode = " + singleton1.hashCode());
        System.out.println("singleton2的hashCode = " + singleton2.hashCode());
    }
}

优缺点说明:

这种方式采用了类装载机制来保证初始化实例时只有一个线程。

静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。

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

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

结论:  推荐使用。

2.7 枚举

package com.szh.singleton.type7;
/**
 * 枚举
 */
enum Singleton {
    INSTANCE;
}
public class SingletonTest07 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.INSTANCE;
        Singleton singleton2 = Singleton.INSTANCE;
        System.out.println(singleton1 == singleton2);
        System.out.println("singleton1的hashCode = " + singleton1.hashCode());
        System.out.println("singleton2的hashCode = " + singleton2.hashCode());
    }
}

优缺点说明:

借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。

这种方式是Effective Java作者Josh Bloch提倡的方式。

结论:  推荐使用。

3.单例模式在JDK中的应用(简单的源码分析)

我们可以看一下有一个类叫 Runtime,位于java.lang包下的。

从这个类的源码中可以看到,它首先是创建了一个私有的本类实例对象,然后最下面就是构造方法私有化,中间的公共方法则是提供给外部的,外部类可以通过这个方法来获取到Runtime这个类的实例对象。这不就是我们上面所说的单例模式吗?这里它采用的是饿汉式写法。

4.单例模式总结

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

当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new。

单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即: 重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session 工厂等)。

以上就是java编程创建型设计模式单例模式的七种写法示例详解的详细内容,更多关于java创建型设计模式单例模式的资料请关注我们其它相关文章!

(0)

相关推荐

  • JAVA设计模式零基础解析之单例模式的八种方式

    目录 单例模式简介: 单例模式优点: 应用场景: 单例设计模式的八种方式: 1.饿汉式(静态常量) 2.饿汉式(静态代码块) 3.懒汉式(线程不安全) 4.懒汉式(线程安全,同步方法) 5.懒汉式(线程安全,同步代码块) 6.双重检查(推荐使用) 7.静态内部类(推荐使用) 8.枚举(推荐使用) 单例模式在JDK应用的源码分析 单例模式注意事项和细节说明 单例模式简介: 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了

  • 深入理解Java设计模式之单例模式

    目录 一.什么是单例模式 二.单例模式的应用场景 三.单例模式的优缺点 四.单例模式的实现 1.饿汉式 2.懒汉式 3.双重加锁机制 4.静态初始化 五.总结 一.什么是单例模式 单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在. 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为.比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息.这种方式简

  • Java23种设计模式中的单例模式你了解吗

    目录 1.定义 2.适用场景 3.常见写法 4.如何防止单例被破坏 1.多线程破坏单例以及解决方法 2.反射破坏单例以及解决方法 3.序列化破坏单例以及解决方法 5.优缺点 6.总结 1.定义 单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点.隐藏其所有的构造方法.属于创建型模式. 2.适用场景 确保任何情况下都绝对只有一个实例. 3.常见写法 第一种:饿汉式单例:在单例类首次加载时就创建实例 /** * @Package: com

  • Java设计模式之单例模式示例详解

    目录 0.概述 1.饿汉式 1.1 饿汉式单例实现 1.2 破坏单例的几种情况 1.3 预防单例的破坏 2.枚举饿汉式 2.1 枚举单例实现 2.2 破坏单例 3.懒汉式 4.双检锁懒汉式 5.内部类懒汉式 6.JDK中单例的体现 0.概述 为什么要使用单例模式? 在我们的系统中,有一些对象其实我们只需要一个,比如说:线程池.缓存.对话框.注册表.日志对象.充当打印机.显卡等设备驱动程序的对象.事实上,这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常.

  • java编程创建型设计模式单例模式的七种示例

    目录 1.什么是单例模式? 2.七种写法 2.1饿汉式(静态常量) 2.2饿汉式(静态代码块) 2.3懒汉式(线程不安全) 2.4懒汉式(线程安全,同步方法) 2.5双重校验锁 2.6静态内部类 2.7枚举 3.单例模式在JDK中的应用(简单的源码分析) 4.单例模式总结 1.什么是单例模式? 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法). 比如Hibernate的 SessionFactory,

  • java编程创建型设计模式工厂方法模式示例详解

    目录 1.什么是工厂方法模式? 2.案例实现 3.JDK中的工厂方法模式 1.什么是工厂方法模式? 工厂方法模式设计方案:  将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现. 工厂方法模式:  定义了一个创建对象的抽象方法,由子类决定要实例化的类.工厂方法模式将对象的实例化推迟到子类. 何时使用?  不同条件下创建不用实例时.方法是让子类实现工厂接口. 2.案例实现 假如说,我们现在有这样一个需求:客户在点披萨时,可以点不同口味的披萨,比如北京的奶酪pizza.北京的胡椒p

  • Java 深入理解创建型设计模式之建造者模式

    1.提出问题 假如说,我们需要建房子:这一过程为打桩.砌墙.封顶.房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不要相同的.3)请编写程序,完成需求. 传统的想法应该就是下面这个类图的形式.. 那么这种写法的优点就是 比较好理解,简单易操作. 缺点则是:设计的程序结构,过于简单,没有设计缓存层对象,程序的扩展和维护不好.也就是说,这种设计方案,把产品(即: 房子)和创建产品的过程(即: 建房子流程)封装在一起,耦合性增强了. 解决方案:  将产品和产品建造过程解耦 

  • Java 深入理解创建型设计模式之原型模式

    1.思考问题 现在有一只羊 tom,姓名为: tom,年龄为:1,颜色为:白色,请编写程序创建和 tom羊属性完全相同的10只羊. 按照传统的思路来,我们可能会按照下面的方式去写. 那么这种写法的优缺点自然而然就出来了: 优点是比较好理解,简单易操作. 缺点是在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低.总是需要重新初始化对象,而不是动态地获得对象运行时的状态,不够灵活. 改进的思路分析:Java中Object类是所有类的根类,Object类提供了一个 c

  • Java 深入理解创建型设计模式之抽象工厂模式

    1.什么是抽象工厂模式? 抽象工厂模式:  定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类. 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合. 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象). 将工厂抽象成两层,AbsFactory(抽象工厂))和具体实现的工厂子类.程序员可以根据创建对象类型使用对应的工厂子类.这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展. 我们仍然以上一篇文章的案例为主,画出抽象工厂模式下的类图

  • Java创建型设计模式之工厂方法模式深入详解

    目录 简单工厂模式 定义产品对象 创建工厂类 工厂使用反射 工厂方法模式 概述 应用场景 优缺点 主要角色 工厂方法模式的基本使用 创建抽象产品 创建具体产品 创建抽象工厂 创建具体工厂 客户端执行 简单工厂模式 简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类的实例,但是它不属于设计模式. 简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心. 定义产品对象 public interf

  • Java创建型设计模式之抽象工厂模式(Abstract Factory)

    目录 抽象工厂模式 概述 产品等级结构与产品族 优缺点 主要角色 抽象工厂模式的基本使用 创建抽象产品 创建具体产品 创建抽象工厂 创建具体工厂 客户端执行 抽象工厂模式 概述 抽象工厂模式(Abastract Factory Pattern)属于创建型模式,它提供了一种创建对象的最佳方式. 它提供一个创建一系列相关或相互依赖对象的接口,无须显式指定他们具体的类.每个生成的工厂都能按照工厂模式提供对象. 抽象工厂模式是围绕一个超级工厂创建其他工厂,该超级工厂又称为其他工厂的工厂. 产品等级结构与

  • 5种Java经典创建型模式详解

    一.概况 总体来说设计模式分为三大类: (1)创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. (2)结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. (3)行为型模式,共十一种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释器模式. 二.设计模式的六大原则 1.开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修

  • Java中单例模式的七种写法示例

    目录 前言 1.饿汉式(线程安全)⭐ 2.懒汉式(线程不安全)⭐ 3.懒汉式(加锁) 4.懒汉式(双重校验锁)⭐ 5.单例模式(静态内部类) 6.单例模式(CAS) 7.单例模式(枚举) 总结 前言 大家好,我是三乙己.考上大家一考:"单例模式的单例,怎样写的?" "不就是构造方法私有化么?" "对呀对呀!--单例模式有七种写法,你知道么?" 言归正传-- 单例模式(Singleton Pattern)可以说是最简单的设计模式了. 用一个成语来形

  • Java编程swing组件JLabel详解以及使用示例

    JLabel 对象可以显示文本.图像或同时显示二者.可以通过设置垂直和水平对齐方式,指定标签显示区中标签内容在何处对齐.默认情况下,标签在其显示区内垂直居中对齐.默认情况下,只显示文本的标签是开始边对齐:而只显示图像的标签则水平居中对齐. 还可以指定文本相对于图像的位置.默认情况下,文本位于图像的结尾边上,文本和图像都垂直对齐. 构造方法介绍: JLabel() 创建无图像并且其标题为空字符串的 JLabel. JLabel(Icon image) 创建具有指定图像的 JLabel 实例. JL

随机推荐