Java设计模式:单例模式

单例模式

基本概念介绍

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

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

单例模式一般实现步骤

  1. 构造器私有化(防止 new)
  2. 类的内部创建对象 向外暴露一个静态的公共方法。
  3. getInstance()拿到唯一的实例对象

单例模式实现方式

饿汉式

顾名思义,饥不择食,无论在什么情况下都会创建实例对象。所以并没有按需创建,没有实现Lazy Loading。这种实现方式优缺点总结如下:

  1. 优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。
  2. 缺点:在类装载的时候就完成实例化,没有达到lazy loading的效果。如果从始至终未用过,则会造成内存的浪费
  3. 这种方式基于classloader机制避免了多线程的同步问题。不过,instance在类装载时就实例化,在单例模式中大多数都是调用getInstance()方法,但是导致类装载的原因有很多种,因此不能确定有其他的方式导致类装载,这时候初始化instance就没有达到lazy loading的效果
    饿汉式单例模式实现方式一般可以用静态常量或者静态代码块来实现
// 饿汉式(静态变量)
class Singleton {
    // 1. 构造器私有化,外部不能new
    private Singleton() {

    }

    // 2. 本类内部创建对象实例
    private final static Singleton instance = new Singleton();

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

/******/
// 饿汉式(静态代码块)
class Singleton1 {

    private static Singleton1 instance;
    
    // 1. 构造器私有化,外部不能new
    private Singleton1() {

    }
    // 2. 在静态代码块中创建单例对象
    static {
        instance = new Singleton1();
    }

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

懒汉式

针对饿汉式存在的可能会导致内存浪费的问题,于是延伸出了懒汉式单例模式。顾名思义,只有在用到它的时候才会装载,且只实例化一次。

但这就又会引入线程安全问题。即在多线程下,一个线程进入到了if(instance == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程下不可用

class Singleton {
    private static Singleton instance;

    private Singleton(){}

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

自然而然的,针对多线程问题,我们会想到加锁来使得线程安全,因此,衍生出懒汉式线程安全的版本。

但由于getInstance()在实际中必然会经常使用,而将整个方法进行同步,会使得效率异常底下。

因此,虽然该方法实现了单例,并且保证了线程安全,但实际开发中并不推荐。

class Singleton {
    private static Singleton instance;

    private Singleton(){}

    // 提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
    // 即懒汉式
    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

双重检查

针对懒汉式、饿汉式各自的优势弊端,双重检查来实现单例模式是较为推荐的方法。Double-Check概念是多线程开发中常使用到的,如下面代码中所示,进行了两次if(instance == null) 检查,这样就能保证线程安全。

并且同时,外部调用getInstance()方法时,不会被方法本身锁住,如果已有实例,便会直接获取到instance对象。当没有实例时,即使有多个线程都进入到了第一层if(instance == null)里,也可以通过第二层的检查使其不创建多个对象。

该方式:
线程安全,延迟加载,效率较高

class Singleton {
    private static volatile Singleton instance;

    private Singleton(){}

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

静态内部类方式

这也是一种比较不错的方式
优缺点说明:

  1. 这种方式采用了类装载的机制来保证初始化实例时只有一个线程
  2. 静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance()方法,才会装载SingletonInstance类,从而完成Singleton的实例化
  3. 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮我们保证了线程的安全性,在类进行初始化时,别的线程无法进入
  4. 优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
  5. 结论:推荐使用
// 使用静态内部类完成单例模式,推荐使用
class Singleton {
    private static volatile Singleton instance;

    private Singleton(){}

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

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
    
	public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                System.out.println(Singleton.getInstance().hashCode());
            }).start();
        }
    }
}

枚举方式

这是Effective Java中所提倡的最优秀的方式。
不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象

// 使用枚举,实现单例模式
enum Singleton {
    INSTANCE; // 属性

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                System.out.println(Singleton.INSTANCE.hashCode());
            }).start();
        }
    }
}
已标记关键词 清除标记
<div> <span style="font-size:16px;"><span><span style="font-size:20px;color:#FF0000;"><strong><span>课程亮点:</span></strong></span></span></span> </div> <div style="font-size:16px;"> <span style="color:#424242;"><span style="background-color:#FFFAA5;">课程培训详细的笔记以及实代码,让学员开始掌握设计模式知识点</span></span> </div> <p style="font-size:16px;"> <span style="font-size:14px;"><span><span style="background-color:#FFFFFF;"><span style="color:#424242;"><br /></span></span></span></span> </p> <div> <div> <span style="font-size:16px;"><span><strong><span style="background-color:#FFFFFF;">课程内容:</span></strong></span></span> </div> <div> <ol><li> <span style="font-size:16px;color:#E53333;"><strong>工厂模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式、原型模型、代理模式模式、适配器模式</strong></span> </li> <li> <span style="font-size:16px;color:#E53333;"><strong>策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式</strong></span> </li> </ol></div> </div> <div style="font-size:16px;"> <span style="color:#FF0000;"><strong><span style="font-size:18px;">课程特色:</span></strong></span> </div> <div> <ol><li> 笔记设计模式,用笔记串连所有知识点,让学员从一点一滴积累,学习过程无压力 </li> <li> 笔记标题采用关键字标识法,帮助学员更加容易记住知识点 </li> <li> 笔记以超链接形式让知识点关联起来,形式知识体系 </li> <li> 采用先概念后实再应用方式,知识点深入浅出 </li> <li> <strong>提供授课内容笔记作为课后复习以及工作备查工具</strong> </li> </ol></div> <p> <span style="font-size:16px;"><span><span style="color:#00B050;"><strong><strong><span style="font-size:18px;">部分图表(电脑PC端查看):</span></strong></strong></span></span></span> </p> <p> <span style="font-size:16px;"><span><span style="color:#00B050;"><strong><strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/201905251242348850.png" alt="" /><img src="https://img-bss.csdn.net/201905251242404542.png" alt="" /><img src="https://img-bss.csdn.net/201905251242469204.png" alt="" /><img src="https://img-bss.csdn.net/201905251242514951.png" alt="" /><img src="https://img-bss.csdn.net/201905251243028561.png" alt="" /><br /></span></strong></strong></span></span></span> </p>
相关推荐
1) 优秀的程序应该是这样的:阅读时,感觉很优雅;新增功能时,感觉很轻松;运行时,感觉很快速,这就需要设计模式支撑。<br /> <br /> 2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,但是不知道怎么使用到真实项目。本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,比如 模式的8种实现方式、工厂模式的3种实现方式、适配器模式的3种实现、代理模式的3种方式、深拷贝等<br /> <br /> 3) 如果你想写出规范、漂亮的程序,就花时间来学习下设计模式吧<br /> <br /> 课程内容和目标<br /> <br /> 本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式<br /> <br /> 1) 内容包括: 设计模式七大原则(一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式模式(8种实现)、抽象工厂模式、原型模式、建造者模式、工厂模式。结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)<br /> <br /> 2) 学习目标:通过学习,学员能掌握主流设计模式,规范编程风格,提高优化程序结构和效率的能力。<br /> <div> <br /> </div>
<p> 本教程为授权出品教程 </p> <p> <br /> </p> <p> <span style="color:#404040;">1) 优秀的程序应该是这样的:阅读时,感觉很优雅;新增功能时,感觉很轻松;运行时,感觉很快速,这就需要设计模式支撑</span><br /> <span style="color:#404040;">2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,但是不知道怎么使用到真实项目。本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,比如 模式的8种实现方式、工厂模式的3种实现方式、适配器模式的3种实现、代理模式的3种方式、深拷贝等</span><br /> <span style="color:#404040;">3) 如果你想写出规范、漂亮的程序,就花时间来学习下设计模式吧</span><br /> <br /> <span style="color:#404040;">课程内容和目标</span><br /> <span style="color:#404040;">本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式</span><br /> <span style="color:#404040;">1) 内容包括:设计模式七大原则(一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式模式(8种实现)、抽象工厂模式、原型模式、建造者模式、工厂模式。结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)。</span><br /> <span style="color:#404040;">2) 学习目标:通过学习,学员能掌握主流设计模式,规范编程风格,提高优化程序结构和效率的能力。</span> </p>
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页