java基础之设计模式之单例模式
关于单例模式:
单例,即单一实例。因为在一些情况下,某些类的对象,我们只需要一个就可以了,所以我们要用到单例模式。
单例模式的目的是使得一个类中的一个静态对象成为系统中的唯一实例,提供一个访问该实例的方法。并阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
单例模式特点:其在整个应用程序的生命周期中只存在一个实例。
单例模式分为懒汉式和饿汉式两种
这里先贴出代码,然后再做解释,便于理解。
懒汉式单例模式核心代码:
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基础之设计模式之单例模式的更多相关文章
- 第二十七节:Java基础面向对象-静态,单例模式,继承详情知识点
前言 Java基础面向对象-静态,单例模式,继承详情知识点.静态-static关键字,static变量,静态代码块,代码块(不加静态),对象创建过程,单例模式,继承. 静态-static关键字 // ...
- java 23 - 2 设计模式之单例模式
单例模式:保证类在内存中只有一个对象. 如何保证类在内存中只有一个对象呢? A:把构造方法私有 B:在成员位置自己创建一个对象 C:通过一个公共的方法提供访问 单例模式之饿汉式: (一进来就造对 ...
- Java基础-单列设计模式
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
- Java进阶篇设计模式之一 ----- 单例模式
前言 在刚学编程没多久就听说过设计模式的大名,不过由于当时还是个彻彻底底的菜鸟,并没有去触碰.直到在开始工作中对简单的业务代码较为熟悉之后,才正式的接触设计模式.当时最早接触的设计模式是工厂模式,不过 ...
- Java中的设计模式之单例模式
Java中的单例模式 设计模式是软件开发过程中经验的积累 一.单例模式 1.单例模式是一种常用的软件设计模式,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控 ...
- Java基础-工厂设计模式(三锅的肥鸡)
---恢复内容开始--- 1)还没有工厂时代:假如还没有工业革命,如果一个你要一架飞机,一般的做法是自己去建造一架飞机,然后拿来开 通常的结果就是 有些时候 要么专科螺钉 没打好 要么就是 那个 ...
- JAVA基础—适配器设计模式
适配器概念 在计算机编程中,适配器模式将一个类的接口适配成用户所期待的.使用适配器,可以使接口不兼容而无法在一起工作的类协调工作,做法是将类自己包裹在一个已经存在的类中. JDK对适配器设计模式的应用 ...
- [Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)
如若转载请注明出处: http://www.cnblogs.com/wang-meng/p/5898837.html 谢谢.上一篇发了一个找工作的面经, 找工作不宜, 希望这一篇的内容能够帮助到大 ...
- 【Java基础】Java设计模式简介
什么是设计模式 设计模式(Design pattern)是一套被反复使用.被多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.设计 ...
随机推荐
- 【工控老马】OPC通讯协议解析-OPC七问
1 通讯步骤 1.1 第一问 OPC Client和OPC Server之间通讯谁是主动的? 答:当然是OPC Client. 1.2 第二问 OPC Client第一次动作做了什么? 答:从大多数O ...
- 使用 Docker 构建和运行自己的镜像
步骤 首先,从 GitHub 中克隆示例项目: git clone https://github.com/dockersamples/node-bulletin-board cd node-bulle ...
- 为什么要避免在 Go 中使用 ioutil.ReadAll?
原文链接: 为什么要避免在 Go 中使用 ioutil.ReadAll? ioutil.ReadAll 主要的作用是从一个 io.Reader 中读取所有数据,直到结尾. 在 GitHub 上搜索 i ...
- hadoop 之 某一个datanode启动失败(Initialization failed for Block pool <registering> (Datanode Uuid unassigned) service to)
环境 集群7台 master 3台 datanode 4台 每个datanode有12个硬盘 场景 启动集群之后,发现有一台datanode未启动,手动启动,还是未启动.查看日志,发现: Initia ...
- C++高并发场景下读多写少的解决方案
C++高并发场景下读多写少的解决方案 概述 一谈到高并发的解决方案,往往能想到模块水平拆分.数据库读写分离.分库分表,加缓存.加mq等,这些都是从系统架构上解决.单模块作为系统的组成单元,其性能好坏也 ...
- 异常 finally
经典面试题: 程序执行结果是100: (一):final和finally和finalize的区别
- 创客系列教程——认识LED灯
认识LED灯 一.初识LED灯 LED灯是一种能够将电能转化为可见光的固态的半导体器件,它可以直接把电转化为光.LED灯逐步融入到生活中的方方面面:室内外的照明.电子指示牌.酷炫的舞台灯光.车辆的 ...
- POJ prime distance
https://oj.shiyancang.cn/Problem/781.html 素数距离,数据范围21亿,如果用素数筛存,并且进行做的话,按照x/lnx计算会是一个非常恐怖的复杂度.确定要做什么, ...
- 最新RabbitMQ安装指南2021.07
一.RabbitMQ入门及安装 1.入门及安装 01 概述 简单概述: RabbitMQ是一个开源的遵循 AMQP协议实现的基于 Erlang语言编写,支持多种客户端(语言),用于在分布式系统中存储消 ...
- 计算机视觉2-> 深度学习 | anaconda+cuda+pytorch环境配置
00 想说的 深度学习的环境我配置了两个阶段,暑假的时候在一个主攻视觉的实验室干活,闲暇时候就顺手想给自己的Ubuntu1804配置一个深度学习的环境.这会儿配到了anaconda+pytorch+c ...