饿汉式单例

public class Hungry{private Hungry(){}public static final HUNGRY = new Hungry();public HUNGRY getInstance(){ //在创建好这个类时这个对象已经实例化return HUNGRY;}
}

懒汉式单例

public class Lazzy{private Lazzy(){}private static Lazzy lazzy = null;public static Lazzy getLazzy(){//在调用这个方法的时候才会实例化这个对象//不调用这个方法则不会创建这个对象 if(lazzy == null){lazzy = new Lazzy();}return lazzy;}
}

普通单例模式在单线程下是没有问题的可以保证每次都创建一个对象 但是在多线程中就不能保证每次创建的是一个对象 当运行以下代码时 可以看到打印的是多个线程 并不能保证每次创建的都是一个对象 代码示例

public class Lazzy{private Lazzy(){//用来测试是否是一个线程(即一个对象)System.out.println(Thread.currentThread().getName()) }private static Lazzy lazzy;public static Lazzy getLazzy(){if(lazzy==null){lazzy = new Lazzy();}return lazzy;}public static void main(String[] args){for(int i = 0; i< 10 ; i++){new Thread(()->{lazzy.getLazzy();}).start();}}
}

双重检查

双重检查就是为了应对这种多线程模式下还能保持单例的一种方式 代码示例

public class Lazzy{private Lazzy(){//测试是否为单例System.out.println(Thread.currentThread().getName());}private volatile static Lazzy lazzy;public static getLazzy(){if(lazzy == null){//DCL懒汉式双重检索synchronized(Lazzy.class){if(lazzy = null){lazzy = new Lazzy(); //不是原子性操作}/***  1.分配内存空间 2.执行构造方法 初始化对象 3.把对象指向内存空间*  在Java虚拟机中 这三个步骤未必会按顺序执行 如果没有按顺序执行直接 return lazzy*  这个时候lazzy并没有初始化完毕 会容易造成指令重排的问题 如果要解决这种问题需要在*  声明这个对象的时候加入volatile关键字*/}}return lazzy;}public static void main(String[] args){for (int i = 0; i < 10; i++) {new Thread(()->{lazzy.getLazzy();}).start();}}
}

再次运行时可以看到每次创建的都是一个线程 即保证了线程的安全性 但是所谓 道高一尺 魔高一丈即便是通过双重检查的模式下可以保证线程安全问题让它来创建一个对象 但是如果通过其他的方式继续来破坏单例模式 那还会保证每次创建都是一个对象么? 单例模式的一个重要特点就是私有构造器 但是如果破坏了这种私有的方式 那它就不是单例了 破坏方式:反射

public class Lazzy{private Lazzy(){}private volatile static Lazzy lazzy;public static Lazzy getLazzy(){if(lazzy == null){synchronized(Lazzy.class){if(lazzy == null){lazzy = new Lazzy();}}}return lazzy;}public static void main(String[] args){Lazzy lazzy = Lazzy.getLazzy();System.out.println(lazzy); //打印第一个对象的内存地址Constructor<Lazzy> declaredConstructor = Lazzy.class.getDeclaredConstructor(null);declaredConstructor.setAccessible(true) //无视私有Lazzy lazzy1 = declaredConstructor.newInstance();System.out.println(lazzy1); //打印第二个对象的内存地址}
}

此时 通过main方法运行可以看到打印的是两个对象的内存地址 也就是说并不是一个对象了 即 单例模式已经被破坏了 如何解决?

三重检索

public class Lazzy{private Lazzy(){//三重检索方式 如果已经创建好Lazzy这个对象从而再次创建对象//则会手动抛出一个异常synchronized(Lazzy.class){if(lazzy != null){throw new RuntimeException("不要通过反射来破坏单例模式");}}       }private volatile static Lazzy lazzy;public static Lazzy getLazzy(){if (lazzy == null){//DCL懒汉式 双重检索synchronized (Lazzy.class) {if (lazzy == null){lazzy = new Lazzy(); //不是原子性操作}/***  1.分配内存空间 2.执行构造方法 初始化对象 3.把对象指向内存空间*  在Java虚拟机中 这三个步骤未必会按顺序执行 如果没有按顺序执行直接 return lazzy*  这个时候lazzy并没有初始化完毕 会容易造成指令重排的问题 如果要解决这种问题需要在*  声明这个对象的时候加入volatile关键字*/}}return lazzy;}public static void main(String[] args){Lazzy lazzy = Lazzy.getLazzy();System.out.println(lazzy);//使用反射破坏单例模式Constructor<Lazzy> declaredConstructor = Lazzy.class.getDeclaredConstructor(null);declaredConstructor.setAccessible(true);Lazzy lazzy1 = declaredConstructor.newInstance();System.out.println(lazzy1);}
}

再次运行代码 可以看到首先会打印 创建好的Lazzy对象的内存地址 然后会抛出个异常对象 继而输出异常对象信息:不要通过反射来破坏单例模式

总结:

饿汉式:类一旦加载 就把单例初始化完成  保证getInstance的时候 单例是已经存在的了 线程安全 可以用于多线程不会出现问题

懒汉式:顾名思义 比较懒 只有当调用getLazzy()方法的时候,才回去初始化这个单例 线程不安全的 多线程模式下需要进行双重检查的方式来保证每次只创建一个实例如果双重检查后又通过反射的方式来破坏这个单例还要用到三重检索的方式来保证单例

单例设计模式中三重检索相关推荐

  1. (单例设计模式中)懒汉式与饿汉式在多线程中的不同

    /*目的:分析一下单例设计模式中,懒汉式与饿汉式在多线程中的不同!开发时我们一般选择饿汉式,因为它简单明了,多线程中不会出现安全问题!而饿汉式需要我们自己处理程序中存在的安全隐患,但是饿汉式的程序技术 ...

  2. 单例设计模式中懒汉式和饿汉式的区别?

    什么时候创建.安全方面.实现方式 1.基本了解 懒汉模式:在类加载的时候不被初始化. 饿汉模式:在类加载的时候就完成了初始化,但是加载比较慢,获取对象比较快. 2.安全方面 懒汉模式在创建对象时不加上 ...

  3. 对于java程序语言的单例设计模式讲解

    1.设计模式:解决某一类问题最行之有效的方法.(java中有23种通用设计模式) 单例设计模式:解决一个类在内存中只存在一个对象. 2.单例设计模式有两种方式: 1)饿汉式 先初始化对象.当类一进内存 ...

  4. java软件设计模式只单例设计模式

    概述 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计 ...

  5. 分析JDK中的Runtime的单例设计模式以及使用小例子

    package july.star.thread23;import java.io.IOException;/*** RunTime * JDK中的一个单例设计模式* @author MoXingJi ...

  6. 笔记:Java中的单例设计模式

    之前接触过单例模式,当初不明白这样的设计用意,今天特地研究了下java中的单例设计模式的用处及用法. 单例模式:单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.一个类 ...

  7. java中饿汉与懒汉的故事(单例设计模式)

    java中的单例设计模式 关于设计模式,这其实是单独存在的东西,它不属于java,但是在java中使用较多,所以今天我就给大家介绍下单例设计模式中的饿汉和懒汉这俩朴素的打工人. 首先我先说明下单例设计 ...

  8. Java中的单例设计模式

    什么是单例设计模式 所谓单例设计模式,就是采取一定的方法保证整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法. 目的:使用着在main方法中就不可以自己创建实例对象 ...

  9. 单例设计模式在Spring中的应用

    一.实现一个单例 可以使用如下的步骤实现一个单例类: 单例设计模式的实现流程 1.将构造方法私有化,使用private关键字修饰.使其不能在类的外部通过new关键字实例化该类对象. 2.在该类内部产生 ...

最新文章

  1. 微信头像可以加皇冠翅膀了,好看!
  2. SQL优化—— 优化insert语句
  3. 用RAM存储器构造能够依次读取各存储单元内容的电路
  4. python123说句心里话的题_如何与回避型依恋的人谈恋爱?
  5. GUN/LINUX命令之 cp mv install
  6. 剑指offer38题
  7. 新网站SEO要做的事情有哪些
  8. python和java哪个好-Python和Java对比,全面解读哪个语言最赚钱,前景最好?
  9. cas server + cas client 单点登录 原理介绍
  10. 11. JavaScript 对象
  11. 计算机u启动无法识别,电脑不识别u盘启动盘
  12. 关于软件工程的目的与意义
  13. 重大噩耗:苹果账号无法付款!(11-20更新:账单地址和卡地址一样,信用卡名字和开发者名字一致,都无法付款)
  14. 服务器装win10性能怎样,普通Win10越升越卡?Win10专业工作站版了解下
  15. 团队项目开发“编码规范”之九:代码分析
  16. Quantifying causality in data science with quasi-experiments
  17. 全球最大多物种水族馆将于5月23日向公众开放,容纳68000多只海洋动物 | 美通社头条...
  18. vue知识(四)生命周期、钩子函数、路由
  19. 靶机17 GROTESQUE: 3.0.1
  20. oracle dba_waiters中的lockid是什么,Oracle 锁机制学习

热门文章

  1. mysql date_format
  2. 半桶水开发 CMPP2.0 with Spring + JPA 2
  3. unity 顶点吸附功能
  4. 计算机控制技术王超,王超 研究生副院长
  5. SSL证书失效导致无法上传问题
  6. pip 提示证书失效
  7. 视频编解码——熵编码的概念
  8. mapstruct 之 类型转换
  9. 工具推荐:串口助手-SerialPort 物联网开发利器
  10. 微信小程序开发——修改页面的背景颜色