java 设计模式之单例模式

java  设计模式之单例模式

前言:

在软件开发过程中常会有一些对象我们只需要一个,如:线程池(threadpool)、缓存(cache)、对话框、偏好设置等。这些对象如果制造出多个实例的话可能会导致一些不必要的麻烦,如:程序行为异常、资源使用过量等。这时单例模式就可以确保一个类只有一个实例,并提供全局访问点。下面是从简单的单例类来探讨该用何种方法实现单例模式。

/**
 * 最经典的单例类
 */
public class Singleton {
  // 设置成静态变量来记录Singleton的唯一实例
  private static Singleton singleInstance;
  private Singleton(){
    // 构造方法声明为私有的,这样只能在Singleton类中才能调用此构造方法
  }
  /*
   * 获取Singleton对象,如果还未实例化则实例化一个对象并返回这个实例
   */
  public static Singleton getInstance(){
    if (singleInstance == null) {
      singleInstance = new Singleton();
    }
    return singleInstance;
  }
  // 其他方法
}

从上面的例子可以看出Singleton类自己管理这个类的实例化过程,而且提供了全局访问点,就是设置成静态的getInstance()方法,在其他类要使用Singleton时它会返回一个实例。这中单例模式有个优点就是延迟实例化,简单地说延迟实例化就是延迟初始化,在类需要时才创建其实例,而不是在开始加载这个类时就创建出一个实例,这样的好处是可以避免性能的浪费。例如有些对象无需程序一开始就使用,或者其在程序执行的过程中就没有使用过。但是此例子却又一个缺点,那就是线程不够安全。因为如果有多个线程同时执行到getInstance()方法,而Singleton又还未new Singleton()一个实例,那么线程就会都认为singleInstance为null,就都会实例化Singleton,这时就会产生多个Singleton实例,明显不符合单例模式的初衷。那么接下来可能要做的就是对其进行改进

public class SingletonA {
  private static SingletonA singletongA;
  private SingletonA(){

  }
  /*
   * 增加synchronized关键字把getSingletonA方法变为同步方法
   */
  public static synchronized SingletonA getInstanceA(){
    if (singletongA == null) {
      singletongA = new SingletonA();
    }
    return singletongA;
  }
  // 其他方法
}

从这个例子上看增加了synchronized可以使getInstanceA()变成一个同步的方法,这时线程在进入这个方法之前就需要等待其他线程离开这个方法才能进入,也就使得该方法只能同时存在一个线程在执行它。

可能差不多问题解决了,但是要知道同步方法是会影响程序执行效率的,在此例子中我们只是为了解决第一个例子中第一次执行getInstance()方法不会产生多个实例,而这个例子中却会导致每次需要实例时都会调用getInstanceA()同步方法,而在已经有实例之后的调用synchronized就会是累赘,因为我们已经无需担心这个单例类会再次被创建出新的实例。因此我们还需要做一下改进。

既然上面说到延迟实例化,那么如果是不用的话那就简单多了。

public class SingletonB {
  // 在静态初始化器(static initializen)中创建单例,保证线程安全
  private static SingletonB singletonB = new SingletonB();
  private SingletonB(){
    // 构造函数
  }
  public static SingletonB getInstaceB(){
    // 已经实例化了,直接使用它
    return singletonB;
  }
}

上面的这种做法是在JVM加载这个类时马上创建一个实例,因为JVM会在线程访问这个实例之前就创建出该实例,因此线程是安全的。但这相较于延迟实例化而言可能会出现资源的浪费。而且如果此类较大的情况下会时程序初始化时间加长。

那么是否可以在使用用延迟实例化的同时又不会造成线程不安全且增加访问效率呢。接下来就用双重检查加锁来改进一下。

/**
 * 双重锁单例模式
 */
public class SingletonC {
  private volatile static SingletonC singletonC;
  private SingletonC(){

  }
  public static SingletonC getInstanceC(){
    if (singletonC == null) {
      synchronized (SingletonC.class) {
        if (singletonC == null) {
          singletonC = new SingletonC();
        }
      }
    }
    return singletonC;
  }
}

上面的例子是先检查实例,如果不存在则进入同步区块,进入同步区块之后再次检查,如果还是null才会创建实例,因而singletonC = new SingletonC()只会执行一次,而之后调用getInstanceC()时就因为有实例直接返回,所以除了第一次调用时会走同步,而之后便不会如第二个例子那样每次都会走同步方法。这样就可以使得执行getInstanceC()的时间减少。想必这里会发现有个volatile关键字,其作用是使得singletonC被初始化后对所有线程可见,多个线程可以正确地处理这个SingletonC变量。但要注意的:volatile关键字只能在Java 5及其之后使用,如果在此版本之前会导致这个双重检查失效。

在使用单例模式时,如果有多个类加载器(classloader)时需要自行指定类加载器,并指定用一个类加载器。因为每个类加载器都定义了一个命名空间,不同的类加载器可能会加载同一个类,从而导致单例类创建出多个实例。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • java设计模式之单例模式学习

    1 概述 单例模式有几个好处: (1)某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销. (2)省去了new操作符,降低了系统内存的使用频率,减轻GC压力. (3)有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了. 2 详解 单例模式常用的写法有如下这么两种. 2.1 饿汉式 如果应用程序总是创建并使用单例模式,或者在创建和运行时压力不是很大的情况下,可以使用一个私有静态变量,提前把对象创建好. 复制代码 代码如下: package org.sc

  • C++和java设计模式之单例模式

    单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点.其构造过程由自身完成,可以将构造方法定义为private型的,这样外界就只能通过定义的静态的函数Instance()构造实例,这个函数的目的就是返回一个类的实例,在此方法中去做是否有实例化的判断.客户端不再考虑是否需要去实例化的问题,把这些都交给了单例类自身.通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象.一个最好的办法,就是让类自身负责保存它的唯一实例.这个类可以保证没有其他实例可

  • 浅析Java设计模式编程中的单例模式和简单工厂模式

    单例模式 动机 有时候只有一个类的实例是很重要的.比如,一个系统应该只有一个窗口管理实例. 单例模式是最简单设计模式:类负责实例化自己,确保只有一个实例,并且提供一个访问这个实例的入口. 目的 1. 确保只有一个实例被创建. 2. 提供访问这个实例的入口. 使用final确保被创建一次,private的构造函数确保不被实例化.public的getInstance方法确保外部能够访问.下面是饿汉模式: public class Singleton { private static final Si

  • Java设计模式之单例模式实例分析

    本文实例讲述了Java设计模式之单例模式.分享给大家供大家参考,具体如下: 单例模式:(Singleton Pattern)是一个比较简单的模式,其定义如下: Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例) 单例模式,很简单的一个模式.其实在android开发中,很多地方都会用到单例模式,比如某些工具类.Json数

  • 深入解析Java的设计模式编程中单例模式的使用

    定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 类型:创建类模式 类图: 类图知识点: 1.类图分为三部分,依次是类名.属性.方法 2.以<<开头和以>>结尾的为注释信息 3.修饰符+代表public,-代表private,#代表protected,什么都没有代表包可见. 4.带下划线的属性或方法代表是静态的. 5.对类图中对象的关系不熟悉的朋友可以参考文章:设计模式中类的关系. 单例模式应该是23种设计模式中最简单的一种模式了.它有以下几个要素: 私有的构

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

    单例模式是非常常见的设计模式,其含义也很简单,一个类给外部提供一个唯一的实例.下文所有的代码均在github 源码整个项目不仅仅有设计模式,还有其他JavaSE知识点,欢迎Star,Fork 单例模式的UML图 单例模式的关键点 通过上面的UML图,我们可以看出单例模式的特点如下: 1.构造器是私有的,不允许外部的类调用构造器 2.提供一个供外部访问的方法,该方法返回单例类的实例 如何实现单例模式 上面已经给出了单例模式的关键点,我们的实现只需要满足上面2点即可.但是正因为单例模式的实现方式比较

  • java设计模式之单例模式解析

    单例模式是最简单但同时也是很重要的一种设计模式,优点有以下几个方面: 1.当内存占用特别大的类需要频繁地创建销毁时,单例模式可以节省内存和提高性能,例如myBatis里面的sessionFactory 2.当需要对文件做单一读写时,例如同一时间只能同时写入一个windows文本文件,则需要用单例来避免多重读写 缺点是: 1.单例模式没有接口,很难对其进行拓展. 2.不利于测试,没办法直接根据接口mock出一个对象出来测试 最后说下其实现方式主要有饿汉模式和懒汉模式.其中懒汉模式又可以细分为几种,

  • java设计模式之单例模式的详解及优点

    java设计模式之单例模式 定义:如果一个类始终只能创建一个实例,那么这个类被称为单例类,这种设计模式被称为单例模式. Spring框架里面可以将所有生成的bean对象都设置为单例模式,只需要在配置Bean实例时指定scope="singleton"即可,或者不做配置默认即为单例模式. 我们可以创建一个小的Demo来演示单例模式的实现,只需要保证该类只能创建一个实例,我们可以用权限修饰符private修饰该类的构造器. 提供一个创建该类的接口,该接口只能用static修饰,类里面创建一

  • java设计模式之单例模式

    单例模式也叫做单肩模式,也是一种创建型模式,是我们日常开发中最常使用的一种设计模式,经常被用来封装一些工具类,例如数据库连接等. 单例模式的定义: 单例模式,是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例.即一个类只有一个对象实例 单例模式分为以下几种: ①饿汉单例模式 ②懒汉单例模式 ③IoDH单例模式 ④枚举单例模式 下面我们一一的进行介绍: 1.首先是饿汉单例模式,顾名思义"饿汉",代表急着"吃饭&q

  • 简单讲解在Java编程中实现设计模式中的单例模式结构

    1. 模式介绍 模式的定义 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 模式的使用场景 确保某个类有且只有一个对象的场景,例如创建一个对象需要消耗的资源过多,如要访问 IO 和数据库等资源. 2. UML类图 角色介绍: (1)Client : 高层客户端. (2)Singleton : 单例类. 3. 模式的简单实现 public class Singleton { private static Singleton intance; private Singleton(

随机推荐