单例模式之懒汉式单例模式

本文将探讨三种懒汉式单例模式,会从代码的运行效率,线程安全等方面探讨。

在上一篇文章中,刚刚介绍饿汉式单例模式,在本文开头先简单的说一下懒汉式单例模式和饿汉式单例模式的区别:
首先懒汉式单例模式,是在程序需要用到该实例时才会创建的。这样就不会像饿汉式一样,在类加载过程中就会创建。这样就减少了内存的浪费,当然也自然而然的带来了一些缺点:需要时才创建,影响程序的执行效率。另外,懒汉式单例模式在使用时进行创建,势必会带来线程安全的问题,需要解决以上问题,就需要用到锁。锁的使用也在一定程度上会带来一定的执行效率问题。

第一种:普通的懒汉式单例模式
直接上代码:

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

这种设计明显的一个问题就是执行效率低,无论是否已经存在实例,在多线程的情况下都会发生阻塞。
对以上代码进行改进,首先让当程序中实例存在的时候,直接返回实例,不需要抢占锁。当程序中不存在实例时,再抢占锁进行创建。根据以上的思想,出现了第二种懒汉式方式:

第二种:双重判断型单例模式

public class LazyDoubleCheckSingleton {private LazyDoubleCheckSingleton() {}private volatile static LazyDoubleCheckSingleton instance;public static LazyDoubleCheckSingleton getInstance() {//确定是否需要阻塞if (instance == null) {synchronized (LazyDoubleCheckSingleton.class) {//确定是否需要创建实例if (instance == null) {//这里在多线程的情况下会出现指令重排的问题,所以对共有资源instance使用关键字volatile修饰instance = new LazyDoubleCheckSingleton();}}}return instance;}}

对于第二种方式,较第一种方式而言,性能提高了。但是代码的可读性差了。

第三种:利用java语法本身特性

public class LazyStaicSingleton {private LazyStaicSingleton(){}public static LazyStaicSingleton getInstance(){return Hander.INSTANCE;}private static class Hander{private static final LazyStaicSingleton INSTANCE=new LazyStaicSingleton();}
}

针对以上三种方式,都可以通过反射破坏其单例模式的特性,这个时候可以在私有构造方法种如下设计:

  private LazyStaicSingleton(){if(Hander.INSTANCE!=null){throw new RuntimeException("不允许非法访问");}}

这样在通过反射创建实例时就会报错。

测试代码如下:

public class LazyStaticSingletonTest {public static void main(String[] args) {//先创建一个实例LazyStaicSingleton instance=LazyStaicSingleton.getInstance();System.out.println(instance);//通过反射创建实例try{Class<?> clazz=LazyStaicSingleton.class;Constructor c = clazz.getDeclaredConstructor(null);c.setAccessible(true);Object lazyStaicSingleton=c.newInstance();}catch (Exception e){e.printStackTrace();}}
}

结果:

java.lang.reflect.InvocationTargetExceptionat sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.lang.reflect.Constructor.newInstance(Constructor.java:423)at com.example.singleton.LazyStaticSingletonTest.main(LazyStaticSingletonTest.java:17)
Caused by: java.lang.RuntimeException: 不允许非法访问at com.example.singleton.lazy.LazyStaicSingleton.<init>(LazyStaicSingleton.java:6)... 5 more

单例模式之懒汉式单例模式相关推荐

  1. 饿汉式单例模式与懒汉式单例模式

    饿汉式单例模式 GiantDragon 应该只有一只,通过私有化其构造方法,使得外部无法通过new 得到新的实例. GiantDragon 提供了一个public static的getInstance ...

  2. 懒汉单例模式 java_Java懒汉式单例模式详解

    标签: 单例模式最常见的有两种,饿汉式和懒汉式两种.本文先简单说一下懒汉式单例,再着重叙述饿汉式单例,饿汉式单例是本文的叙述重点. 懒汉式的优点是:写起来比较简单,而且不存在多线程同步问题,避免了sy ...

  3. 设计模式-单例模式-注册式单例模式-枚举式单例模式和容器式单例模式在Java中的使用示例

    场景 设计模式-单例模式-饿汉式单例模式.懒汉式单例模式.静态内部类在Java中的使用示例: 设计模式-单例模式-饿汉式单例模式.懒汉式单例模式.静态内部类在Java中的使用示例_霸道流氓气质的博客- ...

  4. 单例模式可以分为懒汉式和饿汉式:     懒汉式单例模式:在类加载时不初始化。     饿汉式单例模式:在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快。

     单例模式可以分为懒汉式和饿汉式: 懒汉式单例模式:在类加载时不初始化. 饿汉式单例模式:在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快.

  5. JAVA单例模式:懒汉式,饿汉式

    今天复习了一下java的单例模式,写了懒汉式和饿汉式的实现例子.代码如下: 1.懒汉式单例 package com.lf.shejimoshi;/*** @classDesc: 类描述:(懒汉式单例测 ...

  6. 【Java多线程】实现Runnable接口方式 / 继承Thread类方式;使用synchronized锁实现线程安全;线程安全的懒汉式单例模式;死锁问题示例

    Thread 的生命周期 一.实现Runnable接口方式 1.在 run 方法中使用 synchronized 块 /*** 例子:创建三个窗口卖票,总票数为100张.使用实现Runnable接口的 ...

  7. 单例模式之懒汉式/饿汉式/结合二者之优的模式

    单例模式主要用来产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例. 两个好处: 对于频繁使用的对象,可以省略new操作花费的时间 new的次数少了,对系统内存的使用频率就小了,那么GC压力 ...

  8. Java双重检查懒汉式单例模式中volatile的作用

    先看下懒汉式单例模式双重检查的写法 public class Lazy2 {private volatile static Lazy2 instance;private Lazy2 (){}publi ...

  9. java单例模式_懒汉式

    懒汉式单例模式 步骤 1.仍然将构造器私有化 2.定义一个静态属性 3.提供一个公共的static方法,可以返回一个Cat对象 4.懒汉式,只有用户创建getInstance时,才能返回cat对象 p ...

最新文章

  1. 用keras作CNN卷积网络书本分类(书本、非书本)
  2. linux s t i a权限,关于Linux下s、t、i、a权限
  3. PHP cURL应用实现模拟登录与采集使用方法详解
  4. linux 下/proc/cpuinfo三级缓存,51CTO博客-专业IT技术博客创作平台-技术成就梦想
  5. 案例 -- web移动端项目(vue)
  6. 大一c语言程序考试常考程序题,C语言程序常考题
  7. 地图索引文件MXD保存到数据库中
  8. matlab里impz指令格式,华北电力大学Matla实验指导书.doc
  9. 云上PDF怎么删除页眉页脚_word页眉处理技巧:用VBA快速删除批量页眉页脚
  10. 20189319《网络攻防》第二周作业
  11. 获取字符串被分割后的总数组长度 java 类似UBound()方法
  12. Android小心心动画
  13. Unity和AndroidStudio交互制作SDK并和其他的SDK合并(微信APP支付)
  14. bsdiff算法c语言实现,bsdiff的使用
  15. landsat5数据下载1985年中国地区
  16. 1225:金银岛 题解
  17. selenium的常见方法及使用
  18. scala:查询圆周率pi
  19. ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 A Saving Tang Monk II【分层bfs】
  20. 计算属性computed里面的getter和setter

热门文章

  1. Stub和Mock的区别
  2. 认识信道(零):天线的极化
  3. php yii2框架仿站教程,从零开始学YII2框架(六)高级应用程序模板,yii2框架
  4. 浅析深度学习中的mask操作
  5. userdel、usermod命令详解
  6. 华为日历登录qq邮箱的解决方案
  7. Python实现多任务
  8. 免费ARP(gratuitousARP)
  9. 红米2a android5,红米手机/小米手机2S/2A三机对比图赏
  10. python numpy.ndarray中的数据转为int型