单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。

今天我们不谈单例模式的用途,只说一说如果在面试的时候面试官让你敲一段代码实现单例模式的情况下怎样写出让面试官眼前一亮的单例代码。因为笔者学的是Java,所以接下来的实例将用Java语言编写。

说到单例模式,第一个想到的是该类中有一个初始化为null的自身引用,且被private修饰符修饰,其它类不得直接访问。除此之外,单例模式的类还需要有private的构造方法,这一点不难理解,如果构造方法是public的,那么类外部可以直接调用该类的构造方法,如此一来便不具备单例的特性。那么怎么获取该类唯一的实例呢?这就需要一个公有的获取器,该方法返回值类型是单例模式类,返回的结果自然是该类中唯一的实例。思路有了,我们便可以实现最简单的单例模式类:

不得不说,这样的做法确实达到了单例模式的要求,正常情况下系统中只有一个Singleton的对象。但是如果存在并发的情况呢?两个用户同时访问该类的获取器,此时假设Singleton对象还未被实例化,那么系统将会两次调用构造方法,这样一来系统中就会存在两个Singleton类的实例。说明这种方式的单例没有考虑到并发情况,说明面试者只是粗略的了解单例模式,并没有加以深入思考,想让面试官满意?呵呵。。。。。。

Java相较于C++而言个人认为编程的难易度上来说要容易很多。在考虑线程同步时一个synchronized关键字便能解决普通加锁问题。synchronized关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。也就是说当两个线程同时访问类中synchronized方法或代码块时,只能有一个线程执行其代码,另一个只能等待当前线程调用结束后才能访问。这下子单例的实现就so easy了!只要对代码稍加改动即可:

这样的写法面试官会觉得你这个面试者在思考问题的时候比较全面,考虑到并发的情况,相较之前的方式面试官会觉得:少年,很有前途哦!

然而光是让面试官看好是不够的,我们要让他欣赏,通过单例这样的小问题便能拿到offer。也就是说第二种实现方式是可以进行优化的。如何优化呢?我们看到,当前系统中每次调用获取方法时便会进行加锁,而加锁需要的时间便是我们可以进行优化的地方。现在我所想的是我们只需要在第一次调用时加一次锁往后便再也不不需要加锁了,这样一来便省下了每次调用加锁的时间,虽然计算机执行加锁的时间很短但久而久之也是相当长的一段时间。

那么怎么实现呢?这需要引入另一个关键字volatile。volatile修饰的话就可以确保instance = new Singleton();对应的指令不会重排序(JVM当发现代码执行顺序变化但结果不变时可能会改变执行顺序来提升自身性能。好坑。。。),也是线程安全的。

如何理解呢?

  1. 线程 1 进入get 方法。

  2. 由于single 为null,线程 1 在 //1 处进入 synchronized块。

  3. 线程 1 被线程 2 预占。

  4. 线程 2 进入get 方法。

  5. 由于single 仍旧为null,线程 2 试图获取 //1 处的锁。然而,由于线程 1 持有该锁,线程 2 在 //1 处阻塞。

  6. 线程 2 被线程 1 预占。

  7. 线程 1 执行,由于在 //2 处实例仍旧为null,线程 1 还创建一个Singleton对象并将其引用赋值给single。

  8. 线程 1 退出 synchronized块并从 get方法返回实例。

  9. 线程 1 被线程 2 预占。

  10. 线程 2 获取 //1 处的锁并检查single 是否为null。

  11. 由于single 是非 null的,并没有创建第二个Singleton对象,由线程 1 创建的对象被返回。

像这样的程序,面试官看完还能不给你offer吗?骚年,前途不可限量啊!

如何写出面试官欣赏的Java单例的更多相关文章

  1. 最后一面挂在volatile关键字上,面试官:重新学学Java吧!

    最后一面挂在volatile关键字上,面试官:重新学学Java吧! 为什么会有volatile关键字? volatile: 易变的; 无定性的; 无常性的; 可能急剧波动的; 不稳定的; 易恶化的; ...

  2. 【JAVA秒会技术之秒杀面试官】秒杀Java面试官——集合篇(一)

    [JAVA秒会技术之秒杀面试官]秒杀Java面试官——集合篇(一) [JAVA秒会技术之秒杀面试官]JavaEE常见面试题(三) http://blog.csdn.net/qq296398300/ar ...

  3. 熟悉的味道——从Java单例写到C++单例

    设计模式中,单例模式是常见的一种.单例模式需要满足以下两个条件: 保证一个类只能创建一个示例: 提供对该实例的全局访问点. 关于单例最经典的问题就是DCL(Double-Checked Lock),今 ...

  4. java单例-积木系列

    一步步知识点归纳吧,把以前似懂非懂,了解表面,知道点不知道面的知识归一下档.   懒汉式单例: 私有化构造函数,阻止外界实例话对象,调用getInstance静态方法,判断是否已经实例化. 为什么是懒 ...

  5. 转:java单例设计模式

    本文转自:http://www.cnblogs.com/yinxiaoqiexuxing/p/5605338.html 单例设计模式 Singleton是一种创建型模式,指某个类采用Singleton ...

  6. Java单例类的简单实现

    对于java新手来说,单例类给我的印象挺深,之前一道web后台笔试题就是写单例类.*.*可惜当时不了解. 在大部分时候,我们将类的构造器定义成public访问权限,允许任何类自由创建该类的对象.但在某 ...

  7. 【Java学习笔记之三十】详解Java单例(Singleton)模式

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

  8. java单例的几种写法

    转载出处:http://cantellow.javaeye.com/blog/838473 第一种(懒汉,线程不安全): public class Singleton { private static ...

  9. java单例五种实现模式梳理

    java单例五种实现模式 饿汉式(线程安全,调用效率高,但是不能延时加载) 一上来就把单例对象创建出来了,要用的时候直接返回即可,这种可以说是单例模式中最简单的一种实现方式.但是问题也比较明显.单例在 ...

随机推荐

  1. 让getElementsByClassName兼容

    function getElementsByClassName(node, classname){ if(node.getElementsByClassName){ //使用现有方法 return n ...

  2. Java模拟http请求调用远程接口工具类

    package ln; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamRea ...

  3. Windows 7安装Oracle 10g的方法

    Windows7下安装Oracle 10g提示"程序异常终止,发生未知错误"的解决方法 1.修改Oracle 10G\database\stage\prereq\db\refhos ...

  4. 关于java中使用数组的几点理解笔记

    1.数组元素就是变量: 2.在已有数据类型之后加方括号[],就会产生一个新的数组类型: 分两类:1)基本数据类型,如:int[],string[]; 2)引用数据类型,如:Person[](类): 3 ...

  5. 超好用的Redis管理及监控工具,使用后可大大提高你的工作效率!

    Redis做为现在web应用开发的黄金搭担组合,大量的被应用,广泛用于存储session信息,权限信息,交易作业等热数据.做为一名有10年以上JAVA开发经验的程序员,工作中项目也是广泛使用了Redi ...

  6. Linux中FTP服务器的搭建

    vmware12上安装的CentOs6.8,最终实现物理机上的windows10能正常访问CentOs上的FTP服务器. 一.查看是否安装有ftp相关的安装包. # rpm -qa | grep vs ...

  7. 跨进程通信之Messenger

    1.简介 Messenger,顾名思义即为信使,通过它可以在不同进程中传递Message对象,通过在Message中放入我们需要的入局,就可以轻松实现数据的跨进程传递了.Messenger是一种轻量级 ...

  8. 【案例分享】SequoiaDB+Spark搭建医院临床知识库系统

    1.背景介绍 从20世纪90年代数字化医院概念提出到至今的20多年时间,数字化医院(Digital Hospital)在国内各大医院飞速的普及推广发展,并取得骄人成绩.不但有数字化医院管理信息系统(H ...

  9. 在当前光标处按指定属性显示字符 - BOIS中断

    在当前光标处按指定属性显示字符 - BOIS中断 最简单的调试方式是打印. 编写MBR时,判断MBR是否加载并运行,最直接的方式就是打印一个字符. INT 0x10 功能描述: 在当前光标处按指定属性 ...

  10. 浅入深出之Java集合框架(上)

    Java中的集合框架(上) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到<浅入深出之Java集合框架 ...