JAVA-初步认识-第十三章-单例模式涉及的多线程问题

一.

单例设计模式之前在谈论的时候,有一部分涉及线程的问题,因此只讲述了一半。现在将其重新描述一下。

单例分为两种表现形式,懒汉和饿汉。

二.

多线程下的单例:饿汉式

懒汉式(延迟加载单例设计模式)

什么时候用到这个对象,再加载它。这个例子并不准备运行,知道就可以。

现在准备将其结合到多线程基础上来,来思考另外一部分内容,叫在多线程情况下,有没有安全隐患。

如果上图的getInstance()方法加入到run方法当中,意味着它将被多线程所执行。多线程执行的时候,涉及到了共享数据(return s),也就是说s是共享数据。它存不存在安全问题呢?它不存在,因为它只有一句,谁来都是返回,都是同一个地址,这是不存在的。而且这里的s已经被final了,固定不变了。这个是没有太大问题的,这是所说的饿汉式。

现在再看一下懒汉式,如果getInsatance放到了run方法当中,就意味着可以被多线程所执行,它有没有安全隐患呢?

我们分析,getInstance方法体中的语句作为多线程运行代码的话,在代码当中有没有共享数据?有的,s就是。有没有多条操作s的语句?有的。

有没有安全问题,验证一下就知道了,不准备通过运行验证,直接分析。核心在于同步的问题。

线程0进来了,s==null么,满足。这时线程0被切换走了,也就是失去了cpu执行权。线程1就进来了,判断s==null么?满足,线程1也切换走了。(这可能么?是可能的,符合cpu随意切换) 这时,0线程获得执行权了,执行了,现在s有对象了,返回了。紧跟着,1线程获取了执行权,根本就不用判断了,直接s=new Single();这时内存中两个对象了,无法保证对象的唯一性了,这就是问题。

问题分析完了,现在怎么解决?

加同步即可。加上synchronized关键字后,第一个线程进来,s是空。即使该线程失去执行权,其他线程也进不来,等到该线程睡醒得到执行权后,继续执行下面的语句,new对象,返回值,最后退出。第二个线程接着进来,一判断s不为空,没事直接拿取这个s就可以了。这就解决问题了。线程安全问题,加了一个synchronized解决了。还没完,多线程在访问的时候,只要有第一个线程进来,它就创建对象了,其他线程过来拿这个对象的时候,它们都要判断锁。在判断s==null之前,还要多判断一下锁。因此,每次拿这个对象前,都要判断这个锁(可能和一定要执行getInstance方法有关),效率比较低。因此,我们说加同步解决线程安全问题,但是降低了效率。为了提高效率,我们准备把代码进行一下改写。

按照以前的写法,synchronized()的括号里写this,但是这里不行。这里是静态的,无法通过该类创建对象,只能是Single.class。

有人说getClass行不行,这不行。写this.getClass也不行,这是一回事。因为getClass方法是非静态的。

用同步代码块和同步函数有区别么?没区别,线程进来后,还是要判断锁,synchronized(Single.class)。

现在修改一下程序,

相当于在进行锁的判断前,先进行了一步判断筛选。

怎么理解呢?视频中是这样设计的,0线程和1线程同时位于synchronized语句前面,if第一次判断的后面。0线程进入同步代码块之后,无论是保有cpu的执行权,还是失去cpu的执行权,1线程都进不来。0线程创建完对象退出后,1线程进来经过判断不符合直接退出。而其它线程在进入getInstance函数后,由于if的第一次判断就不满足,就不用执行同步代码块了,提高了效率。(难道就没有更多的线程集中在synchronized的前面么?这样一来效率就没有提高多少了)

这种双重判断的形式,来解决懒汉式的安全问题和效率问题。这样对比下来,写饿汉式更好,更简单。

面试的时候,会集中在懒汉式。

一般来说,同步函数的锁是this,但是静态函数的锁就不是。

时间: 2024-11-06 18:42:50

JAVA-初步认识-第十三章-单例模式涉及的多线程问题的相关文章

Java学习笔记—第十三章 数据库编程入门

第十三章 数据库编程入门 了解JDBC Java中对数据库的访问主要是通过JDBC进行的.JDBC是Java数据库连接技术(Java Database Connectivity)的简称,是用于执行SQL语句的API,可以为多种关系数据库提供统一访问.由一组用Java语言编写的类和接口组成.(SQL是Structure Query Language的缩写,意义为结构化查询语言,是一种标准的关系数据库访问语言.) JDBC的工作机制 使用JDBC完成对数据库的访问主要包括以下五个层次:Java应用程

java 面向对象编程-- 第十三章 反射、类加载与垃圾回收

1.狭义JavaBean规范 Javabean必须包含一个无参数的public构造方法,方便通过反射的方式产生对象. 属性必须都是私有的. Javabean必须包含符合命名规范的get和set方法,以便访问Javabean的属性. Javabean应该是可序列化(serializable)的. 2.反射 在编译时,并不清楚应该加载哪个类.类的加载是在运行期间进行的.通过反射,可以对类进行加载.探知.自审. 可以通过对象.getClass()或者通过类名.class或者通过Class.forNam

Java编程思想第四版读书笔记——第十三章 字符串

Java编程思想第四版读书笔记--第十三章 字符串 字符串的操作是计算机程序设计中最常见的行为. 关键词: StringBuilder ,StringBuffer,toString(),format转换,正则表达式, 1.不可变String String对象时不可变的.每当把String对象作为方法的参数时,都会复制一份引用.(其实就是对函数中参数列表中参数的操作不会影响外面的原参数) 如下: import static net.mindview.util.Print.*; public cla

Gradle 1.12用户指南翻译——第二十三章. Java 插件

其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://github.com/msdx/gradledoc/tree/1.12. 直接浏览双语版的文档请访问: http://gradledoc.qiniudn.com/1.12/userguide/userguide.html. 另外,Android 手机用户可通过我写的一个程序浏览文档,带缓存功能的,兼容

《Java从入门到精通》第十三章学习笔记

第十三章 Swing程序设计 一.Swing概述 Swing是GUI(图形用户界面Graphic User Interface)开发工具包,在AWT(抽象窗口工具 Abstract Windows Tool)的基础上使开发跨平台的Java应用程序界面成为可能.使用Swing开发的Java程序,其界面是不受本地系统平台限制的. 二.Swing常用窗体 1.JFrame框架窗体 JFrame窗体是一个容器,它是Swing程序中各个组建的载体,可以通过继承java,swing.JFrame类创建一个窗

“全栈2019”Java第四十三章:封装

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第四十三章:封装 下一章 "全栈2019"Java第四十四章:继承 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学习小组". 全栈工程师学习计划

“全栈2019”Java第六十三章:接口与抽象方法详解

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第六十三章:接口与抽象方法详解 下一章 "全栈2019"Java第六十四章:接口与静态方法详解 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学习小组&qu

“全栈2019”Java第八十三章:内部类与接口详解

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第八十三章:内部类与接口详解 下一章 "全栈2019"Java第八十四章:接口中嵌套接口详解 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学习小组&quo

“全栈2019”Java第九十三章:内部类应用场景(迭代器设计模式)

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第九十三章:内部类应用场景(迭代器设计模式) 下一章 "全栈2019"Java第九十四章:局部内部类详解 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学习