Java设计模式单例模式(Singleton)用法解析

这篇文章主要介绍了Java设计模式单例模式(Singleton)用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

单例模式的应用场景:

  单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例。并提供一个全局反访问点。单例模式是创建型模式。单例模式在生活中应用也很广泛,比如公司CEO只有一个,部门经理只有一个等。JAVA中ServletCOntext,ServetContextCOnfig等,还有spring中ApplicationContext应用上下文对象,SessionFactory,数据库连接池对象等。使用单例模式可以将其常驻于内存,可以节约更多资源。

写法:

  1:懒汉模式(线程不安全)

/**
 * 线程不安全的懒汉式单利模式
 *
 * Created by gan on 2019/11/17 17:33.
 */
public class LazySingleton {
  private static LazySingleton instance;

  //构造方法私有化
  private LazySingleton() {
  }

  public static LazySingleton getInstance() {
    if (instance != null) {
      instance = new LazySingleton();
    }
    return instance;
  }
}

  上面的代码,提供一个静态对象instance,构造函数私有化防止外部创建对象,提供一个静态的getInstance方法来给访问者一个单例对象。这种写法的缺点就是没有考虑到线程安全问题,当多个访问者同时访问的时候很有可能创建多个对象。之所以叫懒汉式,是因为这种写法是使用的时候才创建,起到了懒加载Lazy loading的作用,实际开发中不建议采用这种写法。

  2:线程安全的懒汉式(加锁)

/**
 * 线程安全的懒汉式单利模式
 *
 * Created by gan on 2019/11/17 17:33.
 */
public class LazySingleton {
  private static LazySingleton instance;

  //构造方法私有化
  private LazySingleton() {
  }

  public synchronized static LazySingleton getInstance() {
    if (instance != null) {
      instance = new LazySingleton();
    }
    return instance;
  }
}

  这种写法就是在第一种的基础上添加了synchronized关键字保证了线程安全。这种写法在并发高的时候虽然保证了线程安全,但是效率很低,高并发的时候所有访问的线程都要排队等待,所以实际开发中也不建议采用。

  3:恶汉式(线程安全)

/**
 * 饿汉式(线程安全)
 * Created by gan on 2019/10/28 22:52.
 */
public class HungrySigleton {

  public static final HungrySigleton instance = new HungrySigleton();

  private HungrySigleton(){}

  public static HungrySigleton getInstance(){
    return instance;
  }
}

  直接在运行(加载)这个类的时候创建了对象,之后直接访问。显然这种方式没有起到Lazy loading的效果。但是是线程安全的,实际开发中还是比较常用。

  4:静态内部类(线程安全)

/**
 * 静态内部类方式
 * Created by gan on 2019/11/17 17:46.
 */
public class StaticInnerClassSingleton {

  //构造方法私有化
  private StaticInnerClassSingleton() {}

  //内部类
  private static class HolderInnerClass {
    //需要提供单利对象的外部类作为静态属性加载的时候就初始化
    private static StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
  }

  //对外暴漏访问点
  public static StaticInnerClassSingleton getInstance() {
    return HolderInnerClass.instance;
  }
}

  这种内部类跟饿汉式单例有很多相似的地方,相比饿汉式单例模式的区别也是好处在于:静态内部类不在单例类加载时就加载,而是在调用getInstance()方法的时候才进行加载,达到了类似于懒汉式的效果,而且这种方法又是线程安全的。实际开发中也建议采用。

  5:枚举方法单例(线程安全)

/**
 * 枚举单利模式
 * Created by gan on 2019/11/17 17:57.
 */
public enum EnumSingleton {
  INSTANCE;

  public void otherMetthod() {
    System.out.println("需要单利对象调用的方法。。。");
  }
}

  Effective Java作者Josh Bloch提倡的方式,好处有如下:

  1:自由串行化。

  2:保证了一个实例

  3:线程安全

  这种方式防止了单例模式被破坏,而且简洁写法简单,而且绝对的线程安全,但是有个缺点就是不能继承。

  6:双重检查法(通常线程安全,低概率不安全)

/**
 * Double check
 * Created by gan on 2019/11/17 18:03.
 */
public class DoubleCheckSingleton {
  private static DoubleCheckSingleton instance;

  private DoubleCheckSingleton() {}

  public static DoubleCheckSingleton getInstance() {
    if (instance == null) {
      synchronized (DoubleCheckSingleton.class) {
        if (instance == null) {
          instance = new DoubleCheckSingleton();
        }
      }
    }
    return instance;
  }
}

  上面的这种写法在并发极高的时候也可能会出现问题(当然这种概率非常小,但是毕竟还是有的嘛),解决的方案就是给instance的声明加上volatile关键字即可。于是就出现了下面第7总写法。

  7:Double check(volatile)

/**
 * Double check volatile
 * Created by gan on 2019/11/17 18:03.
 */
public class DoubleCheckSingleton {
  private volatile static DoubleCheckSingleton instance;

  private DoubleCheckSingleton() {}

  public static DoubleCheckSingleton getInstance() {
    if (instance == null) {
      synchronized (DoubleCheckSingleton.class) {
        if (instance == null) {
          instance = new DoubleCheckSingleton();
        }
      }
    }
    return instance;
  }
}

volatile关键字的其中一个作用就是禁止指令重排序,把instance声明volatile后,对它的操作就会有一个内存屏障(什么是内存屏障?),这样在赋值完成之前,就不会调用读操作。这里具体的原因网上也是众说纷纭,这里不进行具体阐述。

  8:ThreadLocal实现单例模式(线程安全)

/**
 * ThreadLocal实现单利模式
 * Created by gan on 2019/11/17 18:17.
 */
public class ThreadLocalSingleton {

  private static final ThreadLocal<ThreadLocalSingleton> threadLocal = new ThreadLocal() {
    @Override
    protected ThreadLocalSingleton initialValue() {
      return new ThreadLocalSingleton();
    }
  };

  private ThreadLocalSingleton(){}

  public static ThreadLocalSingleton getInstance(){
    return threadLocal.get();
  }
}

  ThreadLocal会为每个线程提供一个独立的变量副本,从而隔离了多个线程堆数据的访问冲突。对于多线程资源共享问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal则采用了“以空间换时间”的方式(主要就是避免了加锁排队)。 前者提供一份变量,让不同的线程排队访问,而后者为每一个线程提供了一份变量,因此可以同时访问而互不影响。但是实际是创建了多个单例对象的。

单例模式的破坏:

  1:序列化破坏

    一个对象创建好以后,有时候需要将对象序列化然后写入磁盘。下次在从磁盘中读取并反序列化,将其转化为内存对象。反序列化后的对象会重新分配内存,即创建型的对象。这样就违背了单例模式的初衷。解决这种方式的方法就是在单例类中新增一个 private Object readResolve();方法即可,具体原因可以看看序列化和反序列化的源码。

  2:反射

    通过反射“暴力破解”也能破坏单例模式,具体暂时不阐述。

  3:克隆

    克隆也会破坏单例模式,具体暂时不阐述。

代码链接:https://gitee.com/ganganbobo/gps-parent

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • java设计优化之单例模式

    单例模式是一种对象创建模式,确保系统中一个类只有一个实例. 在java语言中,这样做有两大好处: 1.对于频繁使用的对象,可以省略创建对象所话费的时间: 2.由于new操作的次数减少,对于系统内存的使用频率降低,这样减少GC的压力,缩短GC停顿的时间. 单例模式细分: 1. public class Singleton{ private Singleton(){ System.out.println("Singleton.Singleton()"); } private static

  • Java设计模式之单例模式实例详解【懒汉式与饿汉式】

    本文实例讲述了Java设计模式之单例模式.分享给大家供大家参考,具体如下: 单例模式就是产生一个对象实例,供外外部访问. 它的应用场景就是在这个类在全局真资源需要统一访问,否则会造成混乱时,才有必要设计成单例. 懒汉式,就是在使用这个对象时,才去查看这个对象是否创建,如果没创建就马上创建,如果已经创建,就返回这个实例. 饿汉式,在加载这个类的时候就先创建好一个对象实例,等待调用. 两者的优缺点也能猜到,使用懒汉式,在反应速度上肯定要比饿汉式慢. 但是这个对象如果不被调用,那就节省了cpu和内存资

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

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

  • Java设计模式之单态模式(Singleton模式)介绍

    定义:Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 在很多操作中,比如建立目录 数据库连接都需要这样的单线程操作. 还有,singleton能够被状态化:这样,多个单态类在一起就可以作为一个状态仓库一样向外提供服务,比如,你要论坛中的帖子计数器,每次浏览一次需要计数,单态类能否保持住这个计数,并且能synchronize的安全自动加1,如果你要把这个数字永久保存到数据库,你可以在不修改单态接口的情况下方便的做到. 另外方面,Singleton也能够

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

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

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

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

  • 23种设计模式(1) java单例模式

    23种设计模式第四篇:java单例模式 定义: 单例模式,是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例.即一个类只有一个对象实例. 特点: 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例 单例模式的要点: 1.私有的构造方法     2.指向自己实例的私有静态引用     3.以自己实例为返回值的静态的公有的方法 单例模式根据实例化对象时机的不同分为两种: 一

  • java 设计模型之单例模式详解

    Singleton 模式的宗旨在于确保某个类只有一个实例,别且为之提供一个全局访问点.为了防止其他工作人员实例化我们的类, 可以为该类创建唯一一个构造器,并将构造器的可见设置为私有.值得注意的是,如果我们创建了其他的非私有的构造器,或者根本没有为该类提 供构造器,那么其他人员还是能实例化我们的类. 如果不希望提前创建单例对象,我们可以等到第一次使用该单例对象的时候在创建它,即 滞后初始化.滞后初始化单例对象有两个理由: 1.也许在静态初始化时间,你没有关于如何初始化单例对象的足够信息. 2.选择

  • Java设计模式单例模式(Singleton)用法解析

    这篇文章主要介绍了Java设计模式单例模式(Singleton)用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 单例模式的应用场景: 单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例.并提供一个全局反访问点.单例模式是创建型模式.单例模式在生活中应用也很广泛,比如公司CEO只有一个,部门经理只有一个等.JAVA中ServletCOntext,ServetContextCOnfig等,还有spri

  • Java String的intern用法解析

    这篇文章主要介绍了Java String的intern用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在Java6中,intern方法返回的是对应字符串在永久态(方法区)中的地址:Java7以后,intern方法返回的是该字符串首次创建时候的堆内存的地址: 在java7中: package com.ecarx.daa.data.manager.utils; public class StringTest { public static

  • Java设计模式模板方法(Template)原理解析

    这篇文章主要介绍了Java设计模式模板方法(Template)原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 前言: 我们在开发中有很多固定的流程,这些流程有很多步凑是固定的,比如JDBC中获取连接,关闭连接这些流程是固定不变的,变动的只有设置参数,解析结果集这些是根据不同的实体对象"来做调整",针对这种拥有固定算法流程,其中有固定的步凑,存在不固定的步凑的情况下就诞生了模板方法模式. 模板方法模式(Template)定义:

  • Java类加载器ClassLoader用法解析

    这篇文章主要介绍了Java类加载器ClassLoader用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 正文 当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化. 一.类加载过程 1.加载 加载指的是将类的class文件读入到内存,并为之创建一个java.lang.Class对象,也就是说

  • Java中Synchronized的用法解析

    简单介绍 synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象: 2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象: 3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象: 4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对

  • JAVA设计模式---单例模式你知道吗

    目录 单例模式的介绍 单例模式实现的八种方式 饿汉式 静态常量 静态代码块 懒汉式 线程不安全的写法 线程安全,同步锁-效率低,不推荐 线程安全,同步代码块-无法解决线程安全问题,不推荐 双重检查-解决线程安全和懒加载问题–推荐使用 静态内部类-可以实现懒加载,线程安全,推荐使用 枚举 单例模式注意事项 总结 单例模式的介绍 单例模式实现的八种方式 饿汉式 静态常量 步骤: 1.构造器私有化(防止new) 2.类的内部创建对象 3.向外暴露一个静态的公共方法-getInstance //饿汉式静

  • Java 构造器原理及用法解析

    导读 构造器是编程的强大组件.使用它们来释放 Java 的全部潜力. 在开源.跨平台编程领域,Java 无疑(?)是无可争议的重量级语言.尽管有许多伟大的跨平台框架,但很少有像 Java 那样统一和直接的. 当然,Java 也是一种非常复杂的语言,具有自己的微妙之处和惯例.Java 中与构造器 constructor有关的最常见问题之一是:它们是什么,它们的作用是什么? 简而言之:构造器是在 Java 中创建新对象object时执行的操作.当 Java 应用程序创建一个你编写的类的实例时,它将检

  • java设计模式-单例模式实现方法详解

    目录 饿汉式 静态变量 静态代码块 懒汉式 线程不安全 线程安全 双重检查 静态内部类 总结 a 饿汉式 所谓饿汉式,就是直接创建出类的实例化,然后用private私有化,对外只用静态方法暴露. 静态变量 步骤 构造器私有化 类的内部创建对象 向外暴露一个静态的公共方法 优点 缺点 写法简单,在类装载的时完成实例化,避免了线程同步问题 类装载时完成实例化,没有达到LazyLoading的效果,若该实例从未使用,则会造成内存浪费 class Singleton { //私有化构造器 private

  • go语言单例模式(Singleton)实例分析

    本文实例讲述了go语言单例模式(Singleton)用法.分享给大家供大家参考.具体分析如下: 单例模式(Singleton):表示一个类只会生成唯一的一个对象.单例模式具有如下性质: A.这些类只能有一个实例: B.这些能够自动实例化: C.这个类对整个系统可见,即必须向整个系统提供这个实例. 复制代码 代码如下: package singleton import "fmt" var _instance *object type object struct {     name st

  • Android 单例模式 Singleton 简单实例设计模式解析

    单例模式 Singleton 简单实例设计模式解析 前言 今天我来全面总结一下Android开发中最常用的设计模式 - 单例模式. 关于设计模式的介绍,可以看下我之前写的:1分钟全面了解"设计模式" 目录 1. 引入 1.1 解决的是什么问题 之前说过,设计模式 = 某类特定问题的解决方案,那么单例模式是解决什么问题的解决方案呢? 含义:单例 =一个实例: 解决的问题:降低对象之间的耦合度 解决方法:单例模式,即实现一个类只有一个实例化对象,并提供一个全局访问点 1.2 实例引入 接下

随机推荐