• Java设计模式之单例模式


    前言

    单例模式在实际项目中起着非常重要的作用,笔者将从以下几点来讲解。

    1.单例模式的概念

    2.单例模式的类图

    3.单例模式的几种表达形式

    单例模式的概念

            单例模式保证某一个具体的类只有一个实例,并且只有自己才能实例化,同时向整个系统开放这个实例。

    单例模式的类图

     

     1 public class Singleton {
     2 
     3     private static final Singleton instance = new Singleton();
     4 
     5     private Singleton () {
     6 
     7     }
     8 
     9     public static Singleton getInstance() {
    10         return instance;
    11     }
    12 }
    Singleton类称为单例类,同时构造函数是以private修饰,防止外部通过new 关键字自行获得实例,同时提供一个获取实例的共有成员函数。因此可以确保在整个系统中,Singleton有且仅有一个实例。

    单例模式的几种表达形式

     单例模式在表达形式上可以分为这么几类

    1.饿汉式

    2.懒汉式

    3.双检锁

    4.静态内部类的方式

    5.静态代码块的方式

    6.枚举的方式

    下面重点来介绍一下前三种方式。

    饿汉式

           饿汉式,既然叫饿汉式,指的就是无论在系统中是否用到该实例,这个实例都会在当类被加载器加载时产生。上述的例子就是饿汉式的通用写法。这种写法不会引起资源的竞争,同时会不会存在线程安全的问题呢?

     1 public class Singleton {
     2 
     3     private static final Singleton instance = new Singleton();
     4 
     5     private Singleton () {
     6 
     7     }
     8 
     9     public static Singleton getInstance() {
    10         return instance;
    11     }
    12 }

    第3行,当某线程A执行到new Singleton()时,没有实例化完成,线程A切换至线程B,因此内存中会出现两份实例?这两份实例指向不同的内存地址?这不就出现了线程的不安全的问题吗?

    懒汉式

     1 public class Singleton {
     2 
     3     private static Singleton instance = null;
     4 
     5     private Singleton () {
     6 
     7     }
     8 
     9     public static Singleton getInstance() {
    10 
    11         if(instance == null) {
    12             instance = new Singleton();
    13         }
    14         return instance;
    15     }
    16 }

    懒汉式和饿汉式刚好相反,懒汉式只有在应用中开始调用该实例时,才回去实例化,同时该实例保存在内存中。不过这种写法基本上在实际项目中不会去采用,因为存在线程安全的问题,当线程A执行到第11行时,线程切换至线程B,线程A和B同时执行new Singleton,因此内存中会出现多份实例的引用,这已经和单例模式的初衷相违背。

    双检锁

    双检锁的写法是为了解决懒汉式写法的线程不安全。具体代码如下所示:

     1 public class Singleton {
     2 
     3     private static Singleton instance = null;
     4 
     5     private static Object monitor = new Object();
     6 
     7     private Singleton () {
     8 
     9     }
    10 
    11     public static Singleton getInstance() {
    12 
    13         if(instance == null) {
    14 
    15             synchronized (Singleton.class) {
    16 
    17                 if(instance == null) {
    18                     instance = new Singleton();
    19                 }
    20             }
    21 
    22         }
    23         return instance;
    24     }
    25 }

     不过也并不是线程绝对的安全。为了保证在高并发下线程安全,需要在instance之前加上关键字volatile,从而保证在多线程之间切换时的可见性,同时防止指令重排序。

    单例模式的优点

    1. 因为在整个应用中,有且只有一个实例,减少了内存的开支,避免了同一对象频繁的创建和销毁,所以大大节省了资源的消耗。

    2.唯一的实例一旦创建,便会保存在内存中,减少系统的开销,尤其是给对象读取较多的资源,比如读取配置文件,一次读取就可以永久的保存在内存中

    3.单例模式保证了对资源的多重占用,比如对一个文件的操作,我们采取线程安全的单例模式进行操作。 

    单例模式的缺点

    1.单例模式是一个单例类,因此没有抽象接口,因此会存在扩展性差的缺点,业务逻辑发生了变化,除了修改类之外没有别的办法,这显然和设计原则中的对修改关闭对扩展开放的原则。

  • 相关阅读:
    多态
    多继承
    传宗接代——继承
    解决vue项目更新版本后浏览器的缓存问题
    escape()、encodeURI()、encodeURIComponent()三种编码方式的区别
    epoll使用总结
    探讨c/c++的指针
    基于linux的pthread_t封装一个Thread类
    unix高并发编程中遇到的问题和笔记
    面向对象分析与设计 实验七
  • 原文地址:https://www.cnblogs.com/sunshine798798/p/9473883.html
Copyright © 2020-2023  润新知