Java中的GOF23(23中设计模式)--------- 单例模式(Singleton)

    在Java这这门语言里面,它的优点在于它本身的可移植性上面,而要做到可移植的话,本身就需要一个中介作为翻译工作,以达到本地和Java的统一,但是就这点而言就相当的消耗资源,所以就Java程序员需要不断的去优化自己的代码。今天所研究的单例模式就是在这样的条件下产生的,

    所谓单例模式,就是只有一个实例,在堆里面只有一个。假如我们的实例,就需要一个,但是会多次用到,这样的话就会出现很尴尬的问题。

    比如:

    1. Windows的TaskManager(任务管理器)就是很典型的只需要一个实例,
    2. Windows的Recycle(回收站)在系统中,回收站只维护一个实例
    3. 在我们的项目里面,会常常使用到读取配置文件的类,
    4. 网站的计数器,一般也采用单例模式,否则难以实现同步
    5. 数据库连接池设计一般也采用单例模式,因为数据库连接是一种数据库资源
    6. 操作系统的文件系统,因为一个操作系统只能有一个文件系统
    7. Application 也是单例模式
    8. Spring中,每个Bean默认就是单例的,这样做的优点是Spring容器可以管理
    9. servlet编程中,每个Servlet也是单例的
    10. 在Spring MVC/struts 1 中,所使用到的控制对象也是单例的

    在上述里面我们了解到,单例模式在我们项目中,几乎是天天出现,所以在这里,我们仔细研究一下,这种设计模式的怎么实现最好(说到实现,它的实现我们大多数人只知道有两种,而还有三种模式知道的人不是很多,以及利用反序列化,反射漏洞去强制解除单例)

  •   饿汉模式

    •   使用static属性来保持对象的单例模式,但是必须在类加载的时候加载,所以没有延迟实例化的性能
       *             而在得到实例的对象中,没有对资源的同步锁,所以调用效率高
       *             而使用JVM类加载器,JVM底层天然是线程安全的,
    • 优点:线程安全调用率较高
    • 缺点:不能延迟加载
       public class Eager_Singleton {
      
           private static Eager_Singleton singleton = new Eager_Singleton();
      
           private Eager_Singleton(){}
      
           public static Eager_Singleton newInstance(){
      return singleton;
      }
      }
  •   懒汉模式 
    •   依旧使用static属性来保持对象的单例模式,但是在方法里面new出来,当我们去调方法的时候,再去加载,就是懒人,懒得一上来就加载,但是就因为在方法里面实例化,所以我们要在该方法上面使用锁的概念来对他进行同步处理,如果不加锁,那我们在A线程里面去掉用它和在B线程里面去调用它他就不是一个概念了

      •  优点:可以延时加载,并且线程是安全的
      • 缺点:就是方法实现了同步,所以资源的利用率比较低。
/**
* 懒汉单例模式
* @author 刘酸酸
*
*/
public class Sluggard_Singleton { private static Sluggard_Singleton singleton = null; private Sluggard_Singleton(){} public synchronized static Sluggard_Singleton newInstance(){
if(singleton == null){
singleton = new Sluggard_Singleton();
}
return singleton;
}
}
  • 双重检测式

    • 将同步块内部下方的代码放至到IF内部
    • 所面临的问题:由于编译器优化等原因JVM底层内部模型的原因,偶尔会出问题,不建议使用。

     

/**
* 双重检查锁实现单例模式
* @author 刘酸酸
*
*/
public class DoubleCheck_Singleton { private static DoubleCheck_Singleton instance = null; public static DoubleCheck_Singleton getInstance() {
if (instance == null) {
DoubleCheck_Singleton sc;
synchronized (DoubleCheck_Singleton .class) {
sc = instance;
if (sc == null) {
synchronized (DoubleCheck_Singleton .class) {
if(sc == null) {
sc = new DoubleCheck_Singleton ();
}
}
instance = sc;
}
}
}
return instance;
} private DoubleCheck_Singleton () { } }
  • 静态内部类方式实现

    • 该方式是结合懒汉式和饿汉式的优点,

     

/**
* 测试静态内部类实现单例模式
* 这种方式:线程安全,调用效率高,并且实现了延时加载!
* @author 刘酸酸
*
*/
public class StaticInnerClass{ private static class StaticInnerClass{
private static final StaticInnerClass instance = new StaticInnerClass();
} private StaticInnerClass(){
} //方法没有同步,调用效率高!
public static StaticInnerClassgetInstance(){
return StaticInnerClass.instance;
} }
  • 枚举实现

    • 在Java的JVM里面就是一种天然的单例模式,那就是枚举类型,如果使用枚举类型的话会受到JVM底层的保护

      • 比如使用反序列化,和使用反射是不能打破这个原则的

    • 优点:上诉

    • 缺点:不能延迟加载

    

/**
* 测试枚举式实现单例模式(没有延时加载)
* @author 刘酸酸
*
*/
public enum Enum_Singleton{ //这个枚举元素,本身就是单例对象!
INSTANCE; //添加自己需要的操作!
public void xxxxx(){
}
}
  • 如何防止反序列化,反射破环单例模式(枚举除外)

    • 在反射中如果我们调用了私有的构造器的话,我们就会抛异常,但是会有人跳过合法检测,这样是可以访问到我们的私有构造器的
import java.lang.reflect.Constructor;

/**
* 测试反射和反序列化破解单例模式
* @author 刘酸酸
*
*/
public class Main{ public static void main(String[] args) throws Exception { //通过反射的方式直接调用私有构造器
Class<Singleton> clazz = (Class<Singleton>) Class.forName("com.suansuan.singleton.Singleton");
Constructor<Singleton> c = clazz.getDeclaredConstructor(null);
//跳过合法检查
c.setAccessible(true);
Singleton s1 = c.newInstance();
Singleton s2 = c.newInstance();
System.out.println(s1);
System.out.println(s2);
  }
}
    • 反序列化时,我们也不能得到一个对象,所以,下述代码解决这两种问题

      /**
      * 测试懒汉式单例模式(如何防止反射和反序列化漏洞)
      * @author 刘酸酸
      *
      */
      public class Singleton implements Serializable {
      //类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。
      private static Singleton instance; private Singleton (){ //私有化构造器
      //反射时,我们作如下操作既可以规避,跳过合法检测的非法访问
      if(instance!=null){
      throw new RuntimeException();
      }
      } //方法同步,调用效率低!
      public static synchronized Singleton getInstance(){
      if(instance==null){
      instance = new Singleton ();
      }
      return instance;
      } //反序列化时,如果定义了readResolve()则直接返回此方法指定的对象。而不需要单独再创建新对象!
      private Object readResolve() throws ObjectStreamException {
      return instance;
      } }

总结:使用枚举去替代饿汉式,使用静态内部类去替代懒汉式

第一次写博客,谢谢大家如果有不对的房指出来,我们共同进步,共同发展,谢谢大家

    

Java中的GOF23(23中设计模式)--------- 单例模式(Singleton)的更多相关文章

  1. Spring中常用的23中设计模式

    1.spring 中常用的设计模式有23中  分类  设计模式  创建型 工厂方法模式(FactoryMethod).抽象工厂模式(AbstractFactory).建造者模式(Builder).原型 ...

  2. Java中的GOF23(23中设计模式)--------- 工厂模式(Factory)

    Java中的GOF23(23中设计模式)--------- 工厂模式(Factory) 在给大家介绍工厂模式之前,我想和大家聊聊面向对象的那点事,在这里,引入三个概念. 开闭原则(Open Close ...

  3. java中的23中设计模式(转)

    设计模式(Design Patterns) --可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  4. java开发中的23中设计模式详解--大话设计模式

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  5. java中的23中设计模式(转载的,有时间一定要熟读)

    设计模式(Design Patterns) --可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  6. java开发中的23中设计模式

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  7. Java开发中的23中设计模式详解(一)工厂方法模式和抽象工厂模式

    一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ...

  8. java开发的23中设计模式

    本文转自  Java开发中的23种设计模式详解(转)   设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓 ...

  9. java的23中设计模式

    一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ...

随机推荐

  1. 《PHP Manual》阅读笔记1

    1.phpinfo() 从 PHP 获取系统信息. 2.$_SERVER 只是 PHP 自动全局化的变量之一.它包含了 web 服务器提供的所有信息,被称为超全局变量. 3.htmlspecialch ...

  2. CSS实现点击事件及实践

    实现原理利用:target,把a标签自身的href以及id设置成一样的. 案例1:实现元素的切换 HTML: <div id="box"> <a href=&qu ...

  3. 动画animation的三个应用(漂浮的白云、旋转的星球、正方体合成)

    × 目录 [1]漂浮的白云 [2]旋转的星球 [3]正方体合成 前面的话 前面介绍过动画animation的详细用法,本文主要介绍动画animation的三个效果 漂浮的白云 [效果演示] [简要介绍 ...

  4. DOM动态脚本和动态样式

    动态脚本 [定义] 在页面加载时不存在,但将来的某一时刻通过修改DOM动态添加的脚本. [方式] [1]插入外部文件方式 var script = document.createElement(&qu ...

  5. Lua 学习笔记(二)语法、类型、值

    首先Lua执行的每一段代码都称之为“程序块”,一个程序块也就是一连串的语句或命令,例如一个源码文件或一行代码.Lua语句之间并不需要分隔符,如代码中的换行就不起任何作用,当然为了养成编码习惯当两条或者 ...

  6. Unity3D协同程序(Coroutine)

    摘要下: 1. coroutine, 中文翻译"协程".这个概念可能有点冷门,不过百度之,说是一种很古老的编程模型了,以前的操作系统里进程调度里用到过,现在操作系统的进程调度都是根 ...

  7. 如何在Notepad++ 中成功地安装Emmet 插件

    对于前端来说,Emmet 是一个好东西,但是好几次在 “Notepad++” 中安装后不能使用.今天认认真真地查找了失败原因,配置完成后,终于可以在 “Notepad++” 下正常使用了.故把过程记录 ...

  8. AngularJS in Action读书笔记4(实战篇)——创建Statistic模块

    个人感觉<Angularjs in action>这本书写的很好,很流畅,循序渐进,深入浅出,关键是结合了一个托管于Github上的实例讲解的,有代码可查,对于初学者应该是个不错的途径.( ...

  9. HTML Inspector – 帮助你编写高质量的 HTML 代码

    HTML Inspector 是一款代码质量检测工具,帮助你编写更优秀的 HTML 代码.HTML Inspector 使用 JavaScript 编写,运行在浏览器中,是最好的 HTML 代码检测工 ...

  10. SQL Server代理(6/12):作业里的工作流——深入作业步骤

    SQL Server代理是所有实时数据库的核心.代理有很多不明显的用法,因此系统的知识,对于开发人员还是DBA都是有用的.这系列文章会通俗介绍它的很多用法. 如我们在这里系列的前几篇文章所见,SQL ...