关于单例模式:

单例,即单一实例。因为在一些情况下,某些类的对象,我们只需要一个就可以了,所以我们要用到单例模式。

单例模式的目的是使得一个类中的一个静态对象成为系统中的唯一实例,提供一个访问该实例的方法。并阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

单例模式特点:其在整个应用程序的生命周期中只存在一个实例。

单例模式分为懒汉式和饿汉式两种

这里先贴出代码,然后再做解释,便于理解。

懒汉式单例模式核心代码:

 1 package com.wxb.singleton;
2
3 public class Singleton_Lazy {
4 /* --创建私有静态的自身实例对象-- */
5 private static Singleton_Lazy uniqueInstance = null;
6
7 /* --私有的构造方法,避免外界利用构造方法创建多个实例-- */
8 private Singleton_Lazy() {
9
10 }
11
12 /* --获取静态实例的方法--
13 * --该方法是静态的,可以通过类名直接调用--
14 */
15 public static Singleton_Lazy getUniqueInstance() {
16 if (null == uniqueInstance) {
17 uniqueInstance = new Singleton_Lazy();
18 }
19 return uniqueInstance;
20 }
21 }

懒汉式单例模式特点:懒汉模式的单例类的唯一实例对象是在第一次使用 getUniqueInstance()时实例化的。如果我们不调用 getUniqueInstance()的话,这个实例是不会存在的,即为 初始值null。可以看出如果不去动它的话,它自己是不会实例化的,所以形象的称之为懒汉模式。

饿汉式单例模式核心代码:

 1 package com.wxb.singleton;
2
3 public class Singleton_Hungry {
4 /*
5 * --在初始化时,就实例化了静态的自身实例对象-- --饿汉式的缺点也在于此:浪费内存--
6 */
7 private static Singleton_Hungry uniqueInstance = new Singleton_Hungry();
8
9 /* --私有的构造方法,避免外界利用构造方法创建多个实例-- */
10 private Singleton_Hungry() {
11
12 }
13
14 /* --获取静态实例的方法--
15 * --该方法是静态的,可以通过类名直接调用--
16 */
17 public static Singleton_Hungry getUniqueInstance() {
18 return uniqueInstance;
19 }
20 }

饿汉单例模式特点:之所以称之为饿汉,是因为肚子饿了,人也会变得主动了,所以饿汉模式下的单例类其自己就会主动实例化该单例类的唯一实例对象。

一般懒汉式单例模式较为常用。

对于唯一实例的验证:

 1 package com.wxb.singleton;
2
3 public class SingletonTest {
4 /* --单例模式唯一实例的测试|调用懒汉式单例验证-- */
5 public static void main(String[] args) {
6 Singleton_Lazy singleton_Lazy1 = Singleton_Lazy.getUniqueInstance();
7 Singleton_Lazy singleton_Lazy2 = Singleton_Lazy.getUniqueInstance();
8 if (singleton_Lazy1.equals(singleton_Lazy2)) {
9 System.out.println("Singleton_Lazy1 and singleton_Lazy2 are the same instance");
10 }
11 else {
12 System.out.println("Singleton_Lazy1 and singleton_Lazy2 are different instance");
13 }
14 }
15 }

输出结果:

可以看出虽然两次调用getUniqueInstance(),但是访问的是同一个实例。

对于懒汉式单例模式,还存在着多线程安全问题

在多线程中,如果在一开始调用 GetUniqueInstance()时,是由两个线程同时调用的,这样的话,两个线程均会进入GetUniqueInstance(),而后由于是第一次调用 GetUniqueInstance(),所以静态变量 uniqueInstance为 null ,这样的话,就会让两个线程均通过 if 语句的条件判断,然后调用 new GetUniqueInstance()了。

所以问题就出来了,因为有两个线程,所以会创建两个实例,这便违反了单例模式的初衷,使得单例模式在多线程中出现不安全的问题。

这个问题我们可以通过线程锁机制对单例模式做相应的优化,即先将一个线程锁定,然后等这个线程完成以后,再让其他的线程访问GetUniqueInstance()中的 if 段语句。

双重校验锁形式单例模式核心代码:

 1 package com.wxb.singleton;
2
3 public class Singleton_Lazy_Safe {
4 /* --创建私有静态的自身实例对象-- */
5 private static Singleton_Lazy_Safe uniqueInstance = null;
6
7 /* --私有的构造方法,避免外界利用构造方法创建多个实例-- */
8 private Singleton_Lazy_Safe() {
9
10 }
11
12 /* --获取静态实例的方法--
13 * --该方法是静态的,可以通过类名直接调用--
14 */
15 public static Singleton_Lazy_Safe getUniqueInstance() {
16 /* --双重校验锁-- */
17 if (null == uniqueInstance) {
18 synchronized (Singleton_Lazy_Safe.class) {
19 if (null == uniqueInstance) {
20 uniqueInstance = new Singleton_Lazy_Safe();
21 }
22 }
23 }
24 return uniqueInstance;
25 }
26 }

关于使用双重校验的原因:

如果有两个线程同时到达,即同时调用了GetUniqueInstance(),此时由于 uniqueInstance == null ,所以两个线程都可以通过第一重的 singleton == null 校验,
进入第一重 if 语句后,由于存在锁机制,所以会有一个线程进入 lock 语句并进入第二重 uniqueInstance == null ,而另外的一个线程则会在 synchronized 语句的外面等待。

当第一个线程执行完 new Singleton_Lazy_Safe()语句后,便会退出锁定区域,此时,第二个线程便可以进入synchronized语句块,此时,如果没有第二重 uniqueInstance == null 的话,那么第二个线程还会继续调用 new Singleton_Lazy_Safe()语句,这样第二个线程又会创建一个 Singleton 实例,违反了“唯一实例”。

由于饿汉式单例类类被加载的时候,就会自行初始化uniqueInstance这个静态的自身实例对象。而不是在第一次调用GetUniqueInstance()时再来实例化单例类的唯一实例,所以饿汉式单例不需要编写多线程安全代码。

java基础之设计模式之单例模式的更多相关文章

  1. 第二十七节:Java基础面向对象-静态,单例模式,继承详情知识点

    前言 Java基础面向对象-静态,单例模式,继承详情知识点.静态-static关键字,static变量,静态代码块,代码块(不加静态),对象创建过程,单例模式,继承. 静态-static关键字 // ...

  2. java 23 - 2 设计模式之单例模式

    单例模式:保证类在内存中只有一个对象. 如何保证类在内存中只有一个对象呢?  A:把构造方法私有  B:在成员位置自己创建一个对象  C:通过一个公共的方法提供访问 单例模式之饿汉式: (一进来就造对 ...

  3. Java基础-单列设计模式

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  4. Java进阶篇设计模式之一 ----- 单例模式

    前言 在刚学编程没多久就听说过设计模式的大名,不过由于当时还是个彻彻底底的菜鸟,并没有去触碰.直到在开始工作中对简单的业务代码较为熟悉之后,才正式的接触设计模式.当时最早接触的设计模式是工厂模式,不过 ...

  5. Java中的设计模式之单例模式

    Java中的单例模式 设计模式是软件开发过程中经验的积累 一.单例模式 1.单例模式是一种常用的软件设计模式,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控 ...

  6. Java基础-工厂设计模式(三锅的肥鸡)

    ---恢复内容开始---   1)还没有工厂时代:假如还没有工业革命,如果一个你要一架飞机,一般的做法是自己去建造一架飞机,然后拿来开 通常的结果就是 有些时候 要么专科螺钉 没打好  要么就是 那个 ...

  7. JAVA基础—适配器设计模式

    适配器概念 在计算机编程中,适配器模式将一个类的接口适配成用户所期待的.使用适配器,可以使接口不兼容而无法在一起工作的类协调工作,做法是将类自己包裹在一个已经存在的类中. JDK对适配器设计模式的应用 ...

  8. [Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)

    如若转载请注明出处: http://www.cnblogs.com/wang-meng/p/5898837.html   谢谢.上一篇发了一个找工作的面经, 找工作不宜, 希望这一篇的内容能够帮助到大 ...

  9. 【Java基础】Java设计模式简介

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

随机推荐

  1. FP增长算法

    Apriori原理:如果某个项集是频繁的,那么它的所有子集都是频繁的. Apriori算法: 1 输入支持度阈值t和数据集 2 生成含有K个元素的项集的候选集(K初始为1) 3 对候选集每个项集,判断 ...

  2. nssm常用命令(在Windows系统下安装服务的工具)

    nssm install servername //创建servername服务 nssm start servername //启动服务 nssm stop servername //暂停服务 ns ...

  3. MySQL测试题——开发公司人事管理系统,包括 Employee表 和 Department表

    一.需求分析 我们的开发团队,计划开发一款公司人事管理软件,用于帮助中小型企业进行更加高效的人事管理.现在需要对数据库部分进行设计和开发,根据对需求和立项的分析,我们确定该数据库中最核心的两个表为员工 ...

  4. Linux查看RAM内存信息

    1.查看/proc/meminfo文件 查看RAM使用情况最简单的方法是通过/proc/meminfo. 这个动态更新的虚拟文件列出了详细的内存使用情况. cat /proc/meminfo 命令输出 ...

  5. 过年有燃放烟花爆竹禁令那我们用css写一个仙女棒烟花看看吧

    先是去找了一张简易画的烟花照片,可以看出主要结构为歪曲的线条结构. 方案一: 弯曲的线条第一反应到的就是"圆角边框": width: 200px; height: 200px; b ...

  6. 双buffer实现无锁切换

    大家好,我是雨乐! 在我们的工作中,多线程编程是一件太稀松平常的事.在多线程环境下操作一个变量或者一块缓存,如果不对其操作加以限制,轻则变量值或者缓存内容不符合预期,重则会产生异常,导致进程崩溃.为了 ...

  7. python中addict模块,设置和读取嵌套字典

    源码地址:   https://github.com/mewwts/addict/blob/master/README.md

  8. mysql数据库主从复制教程

    mysql主从复制教程 架构规划: 192.168.201.150 master 主节点 192.168.201.154 slave 从节点 1. 修改mysql的配置文件(主节点,从节点都要修改) ...

  9. Zuul的应用

    一.介绍 注:Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制.但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了. 二.依赖 <dependency ...

  10. LG1290 欧几里德的游戏

    https://www.luogu.com.cn/problem/P1290 博弈论游戏,用到mod. 辗转相除法的过程,会构成n种状态. 到达最后一个状态就赢了. 对于一次过程如果div>1那 ...