《Head First设计模式》第五章笔记-单件模式

单件模式

定义:确保一个类只有一个实例,并提供全局访问点。

编写格式:

1

2

3

4

5

6

public class MyClass{

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

    public static MyClass getInstance(){  //提供全局访问点

        return new MyClass();

    }

}

有一些对象其实我们只需要一个,比如线程池、缓存、对话框、处理偏好设置和注册表的对象、日志对象。如果制造出多个实例,就会导致程序的行为异常、资源使用过量,或者不一致的结果等。

单件模式实现1:延迟实例化

懒汉式

1

2

3

4

5

6

7

8

9

10

11

12

13

public class Singleton{

    private static Singleton uniqueInstance;//创建一个静态变量来记录Singleton类的唯一实例

    //。。。其他实例变量

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

    //使用getInstance()方法实例化对象

    public static Singleton getInstance(){

        if(uniqueInstance==null){//判断uniqueInstance是否为空,为空则创建实例

            uniqueInstance=new Singleton();

        }

        return uniqueInstance;

    }

    //...其余方法

}

类图:

“延迟实例化”在我们不需要这个实例的时候它将不会产生。

上面的方法的确实现了单件模式,但是在某些情况下将出现一些严重的问题,例如:

在多线程的情况下,可能会创建多个对象。怎么解决多线程单件问题呢?下面有三种方法:

单件模式实现2:通过synchronized关键字解决多线程问题

1

2

3

4

5

6

7

8

9

10

11

12

13

14

class Singleton

{

    private static Singleton singleton;

    private Singleton(){}

    //synchronized关键字迫使每个线程在进入方法前,要先等候别的线程离开该方法

    public static synchronized Singleton getInstance()

    {

        if(singleton == null)

        {

            singleton = new Singleton();

        }

        return singleton;

    }

}

同步(synchronized)可以解决多线程存在的问题,但是同步会降低性能,且第一次执行此方法时才真正需要同步,一旦设置好uniqueInstance变量,就不再需要同步这个方法了,之后每次调用这个方法,同步都是一种累赘。

建议:

1.如果getInstance()d的性能对应用程序不是很关键,则可以忽略同步带来的性能下降问题。

2.同步一个方法可能会让程序执行效率下降100倍,如果getInstance()是程序使用在频繁运行的地方则不建议这样使用。

3.如果应用程序总是创建并使用单件实例或创建运行时的负担不太繁重,可以使用“急切实例化”创建实例,而不用“延迟实例化”的做法。

单件模式实现3:急切实例化

饿汉式

1

2

3

4

5

6

7

8

public class Singleton{

    //在静态初始化器中创建单件,且保证了线程安全

    private static Singleton uniqueInstance=new Singleton();

    private Singleton(){}

    public static Singleton getInstance(){

        return uniqueInstance;

    }

}

利用这个做法,我们依赖JVM在加载这个类时马上创建此唯一的单件实例。JVM保证在任何线程访问uniqueInstance静态变量之前,一定先创建此实例。

单件模式实现4:双重检查加锁

使用双重检查加锁(double-checked locking),首先检查实例是否已经创建了,如果尚未创建,才进行同步。这样一来,只有第一次会同步。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

//在getInstance()中减少使用同步

//注意:双重检查加锁不适用于java1.4以及之前的版本,因为Volatile关键字会导致双重检查加锁失效

class Singleton

{

    //Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。

    //即阻止线程为了优化性能而保有变量的私有拷贝

    private volatile static Singleton singleton;

    private Singleton(){}

    public static Singleton getInstance()

    {           

        if(singleton == null)//检查实例,如果不存在就进入同步区块

        {

            //注意,只有第一次才彻底执行这里的代码

            synchronized(Singleton.class)

            {

                if(singleton == null)//进入区块后,再检查一次

                {

                    singleton = new Singleton();

                }

            }

        }

        return singleton;

    }

}

其他问题:

在Java1.2之前,垃圾收集器有个bug,会造成当单件在没有全局的引用时被当作垃级清除。

多个类加载器(class loader)可能会导致单件失效。

单件模式要点:

  • 单件模式确保程序中一个类最多只有一个实例。
  • 单件模式也提供访问这个实例的全局点。
  • 在Java中实现单件模式需要私有的构造器、一个静态方法和一个静态变量。
  • 确定在性能和资源上的限制,然后小心地选择适当的方案来实现单件,以解决多线程的问题(我们必须认定所有的程序都是多线程的)。
  • 如果不是采用第五版的Java 2,双重检查加锁实现会失效。
  • 小心,你如果使用多个类加载器,可能导致单件失效而产生多个实例。
  • 如果使用JVM1.2或之前的版本,你必须建立单件注册表,以免垃圾收集器将单件回收。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/445425.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《Head First设计模式》第六章笔记-命令模式

封装调用-命令模式 命令模式可将“动作的请求者”从“动作的执行者”对象中解耦。 本篇中将不再描述书中所引入的“巴斯特家电自动化公司”的遥控器控制案例,而使用简单易懂的餐厅案例。 在开始之前,让我们通过一个现实中的例子来了解命令模式。 理解…

一文读懂机器学习库graphLab

文章目录目录什么是graphlab为什么使用graphlab?如何安装graphlab?graphlab的简单使用。目录 什么是graphlab GraphLab 是由CMU(卡内基梅隆大学)的Select 实验室在2010 年提出的一个基于图像处理模型的开源图计算框架,框架使用C语言开发实…

《Head First设计模式》第七章-适配器模式、外观模式

适配器模式 适配器模式是什么,你一定不难理解,因为现实中到处都是。比如说: 如果你需要在欧洲国家使用美国制造的笔记本电脑,你可能需要使用一个交流电的适配器…… 当你不想改变现有的代码,解决接口不适配问题&#…

《Head First设计模式》第八章笔记-模板方法模式

模板方法模式 之前所学习的模式都是围绕着封装进行,如对象创建、方法调用、复杂接口的封装等,这次的模板方法模式将深入封装算法块,好让子类可以在任何时候都将自己挂接进运算里。 模板方法定义:模板方法模式在一个方法中定义一…

机器学习基础-吴恩达-coursera-(第一周学习笔记)----Introduction and Linear Regression

课程网址:https://www.coursera.org/learn/machine-learning Week 1 —— Introduction and Linear Regression 目录 Week 1 Introduction and Linear Regression目录一 介绍1-1 机器学习概念及应用1-2 机器学习分类 二 单变量的线性回归2-1 假设函数hypothesis2…

常见8种机器学习算法总结

简介 机器学习算法太多了,分类、回归、聚类、推荐、图像识别领域等等,要想找到一个合适算法真的不容易,所以在实际应用中,我们一般都是采用启发式学习方式来实验。通常最开始我们都会选择大家普遍认同的算法,诸如SVM&a…

redis——数据结构(字典、链表、字符串)

1 字符串 redis并未使用传统的c语言字符串表示,它自己构建了一种简单的动态字符串抽象类型。 在redis里,c语言字符串只会作为字符串字面量出现,用在无需修改的地方。 当需要一个可以被修改的字符串时,redis就会使用自己实现的S…

Hotspot虚拟机的对象

创建 Step1:类加载检查 虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。 Step2:分…

redis——数据结构(整数集合,压缩列表)

4、整数集合 整数集合(intset)是 Redis 用于保存整数值的集合抽象数据结构, 可以保存 int16_t 、 int32_t 、 int64_t 的整数值, 并且保证集合中不会出现重复元素。 实现较为简单: typedef struct intset {// 编码方…

机器学习知识总结系列- 知识图谱(0-0)

文章目录目录机器学习知识图谱目录 本系列的文章只是根据个人的习惯进行总结,可能结构与一些书籍上不太一样,开始的内容比较简单,会随着后续的深入,不断丰富和更新图谱,同时也期待有相同兴趣的朋友一起给我留言一起丰富…

跳表介绍和实现

想慢慢的给大家自然的引入跳表。 想想,我们 1)在有序数列里搜索一个数 2)或者把一个数插入到正确的位置 都怎么做? 很简单吧 对于第一个操作,我们可以一个一个比较,在数组中我们可以二分,这…

机器学习知识总结系列- 基本概念(1-0)

文章目录目录1. 机器学习的定义2. 机器学习的分类2.1根据是否在人类监督下进行训练监督学习非监督学习半监督学习强化学习2.2根据是否可以动态渐进的学习在线学习批量学习2.3根据是否在训练数据过程中进行模式识别实例学习基于模型的学习3. 机器学习中的一些常见名词4. 机器学习…

剑指offer(刷题21-30)--c++,Python版本

文章目录目录第 21题:解题思路:代码实现:cpython第22 题:解题思路:代码实现:cpython第23 题:解题思路:代码实现:cpython第24 题:解题思路:代码实现…

剑指offer(刷题41-50)--c++,Python版本

文章目录目录第41题:解题思路:代码实现:cpython第42题:解题思路:代码实现:cpython第43题:解题思路:代码实现:cpython第44题:解题思路:代码实现&am…

redis——持久化

因为redis是内存数据库,他把数据都存在内存里,所以要想办法实现持久化功能。 RDB RDB持久化可以手动执行,也可以配置定期执行,可以把某个时间的数据状态保存到RDB文件中,反之,我们可以用RDB文件还原数据库…

剑指offer(刷题51-60)--c++,Python版本

文章目录目录第51题:解题思路:代码实现:cpython第52题:解题思路:代码实现:cpython第53题:解题思路:代码实现:cpython第54题:解题思路:代码实现&am…

2017第一届河北省大学生程序设计竞赛题解

超级密码 小明今年9岁了,最近迷上了设计密码!今天,他又设计了一套他认为很复杂的密码,并且称之为“超级密码”. 说实话,这套所谓的“超级密码”其实并不难:对于一个给定的字符串,你只要提取其中…

大数的四则运算(加法、减法、乘法、除法)

大数的四则运算(加法、减法、乘法、除法) 前言: 在计算机中数字表示的范围是有限制的,比如我们熟知的 int、float、double 等数据类型所能表示的范围都是有限的,如果我们要对位数达到几十位、几百位、上千位的大整数进…

随机过程1

随机过程1概述1.参考书目2.主要内容3.概率论--基本概念回顾3.1对“不确定性”的认识3.2 应对“不确定性”应该怎么做3.3随机变量(Random Variable)3.4分布函数(Distribution Function)3.5概率密度(Density)…