亮点面试题&&实现Singleton(辛格尔顿)模式-JAVA版本
称号:设计一个类。我们只能产生这个类的一个实例。(来自《剑指Offer》)
解析:仅仅能生产一个实例的类是实现Singleton(单例)模式的类型。因为设计模式在面向对象程序设计中起着举足轻重的作业,在面试过程中非常多公司都喜欢问一些与设计模式相关的问题。
在经常使用的模式中,Singleton是唯一一个可以用短短几十行代码完整实现的模式。
因此,写一个Singleton的类型是一个非经常见的面试题。
下面我们给出几种解法。供大家參考。
*不好的解法一:仅仅适用于单线程环境。
因为要求仅仅能产生一个实例。因此我们必须把构造函数设为私有函数以禁止他人创建实例。我们能够定义一个静态的实例,在须要的时候创建该实例。基于这个思路的实现:
public class Singleton1{
private Singleton1(){
}
private final static Singleton1 instance = null;
public static Singleton1 getInstance(){
if(instance == null)
instance = new Singleton1();
return instance;
}
}
上述代码在Singleton1的静态属性Instance中,仅仅有在instance为null的时候才创建一个实例以避免反复创建。同一时候。我们把构造函数定义为私有函数,这样就能确保仅仅创建一个实例。
*不好的解法二:尽管在多线程环境中能工作但效率不高
解法一中的代码在单线程的时候工作正常。但在多线程的情况下就有问题了。设想假设两个线程同一时候执行到推断instance是否为null的if语句。而且instance的确没有创建时,那么两个线程都会创建一个实例,此时类型Singleton1就不再满足单例模式的要求了。
为了保证在多线程环境下我们还是仅仅能得到类型的一个实例,须要加上一个同步锁。把Singleton1稍做改动得到了例如以下代码:
public class Singleton2 {
private static Singleton2 instance = null;
private Singleton2() { }
public static synchronized Singleton2 getInstance() {
if(instance == null) {
instance = new Singleton2();
}
return instance;
}
}
我们还是如果有两个线程同一时候想创建一个实例。因为在一个时刻仅仅有一个线程能得到同步锁。当第一个线程加上锁时,第二个线程仅仅能等待。当第一个线程发现实例还没有创建时,它创建出一个实例。接着第一个线程释放同步锁,此时第二个线程能够加上同步锁,并执行接下来的代码。这个时候因为实例已经被第一个线程创建出来了,第二个线程就不会反复创建实例了,这样就保证了我们在多线程环境中也仅仅能得到一个实例。
可是类型Singleton2还不是非常完美。我们每次通过属性Instance得到Singleton2的实例,都会试图加上一个同步锁,而加锁是一个非常耗时的操作。在没有必要的时候我们应该尽量避免。
**可行的解法一:加同步锁前后两次推断实例是否已存在
我们仅仅是在实例还没有创建之前须要加锁操作,以保证仅仅有一个线程创建实例。而当实例已经创建之后,我们已经不须要再加锁操作了。所以我们改进例如以下:
public class Singleton3 {
private static Singleton3 instance = null;
private Singleton3() { }
public static Singleton3 getInstance() {
if(instance == null) {
synchronzied(Singleton3.class) {
Singleton3 temp = instance;
if(temp == null) {
temp = new Singleton3();
instance = temp
}
}
}
return instance;
}
}
因为指令重排序问题,所以不能够直接写成以下这样:
public class Singleton3 {
private static Singleton3 instance = null;
private Singleton3() { }
public static Singleton3 getInstance() {
if(instance == null) {
synchronzied(Singleton3.class) {
if(instance == null) {
instance = new Singleton3();
}
}
}
return instance;
}
}
可是假设instance实例变量用volatile修饰就能够了,volatile修饰的话就能够确保instance = new Singleton();相应的指令不会重排序,例如以下的单例代码也是线程安全的:
public class Singleton3 {
private static volatile Singleton3 instance = null;
private Singleton3() { }
public static Singleton3 getInstance() {
if(instance == null) {
synchronzied(Singleton3.class) {
if(instance == null) {
instance = new Singleton3();
}
}
}
return instance;
}
}
Singleton3用加锁机制来确保在多线程环境下仅仅创建一个实例,而且用俩个if推断来提高效率。
这种代码实现起来比較复杂,easy出错,我们还有更优秀的解法。
**强烈推荐的解法二:借助内部类
这样的方法属于懒汉式单例,由于Java机制规定,内部类SingletonHolder仅仅有在getInstance()方法第一次调用的时候才会被载入(实现了lazy)。并且其载入过程是线性安全的。内部类载入的时候实例化一次instance。
public class Singleton {
private Singleton() { }
private static class SingletonHolder {
private final static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
版权声明:本文博客原创文章,博客,未经同意,不得转载。
亮点面试题&&实现Singleton(辛格尔顿)模式-JAVA版本的更多相关文章
- 剑指offer之面试题2:实现Singleton模式
来源:剑指offer 这篇主要记录<剑指offer>书籍中的面试题2:实现Singleton模式 使用语言:C# 代码环境:VS2017 总共有5中解法,从前往后依次优化. 结构如下: 前 ...
- 《剑指offer》面试题2:实现Singleton 模式
面试题2:实现Singleton 模式 题目:设计一个类,我们只能生成该类的一个实例. 只能生成一个实例的类是实现了Singleton (单例)模式的类型.由于设计模式在面向对象程序设计中起着举足 ...
- 小菜学习设计模式(二)—单例(Singleton)模式
前言 设计模式目录: 小菜学习设计模式(一)—模板方法(Template)模式 小菜学习设计模式(二)—单例(Singleton)模式 小菜学习设计模式(三)—工厂方法(Factory Method) ...
- 设计模式的征途—1.单例(Singleton)模式
单例模式属于创建型模式的一种,创建型模式是一类最常用的设计模式,在软件开发中应用非常广泛.创建型模式将对象的创建和使用分离,在使用对象时无需关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修 ...
- 转载 单例(Singleton)模式)的误区
在创建型模式中,单例(Singleton)模式和原型(Prototype)模式相对来说其用意更为简单明了.单例(Singleton)模式确保某类只有一个实例,且自行实例化并向整个系统提供这个实例:原型 ...
- c#单例(Singleton)模式实现
sealed class Singleton { private Singleton(); public static readonly Singleton Instance=new Singleto ...
- 创建对象——单例(Singleton)模式
单例(Singleton)模式: 保证一个类在系统里只能有一个对象被实例化. 如:缓存池.数据库连接池.线程池.一些应用服务实例等. 难点:在多线程环境中,保证实例的唯一性. ...
- 剑指Offer面试题:1.实现Singleton模式
说来惭愧,自己在毕业之前就该好好看看<剑指Offer>这本书的,但是各种原因就是没看,也因此错过了很多机会,后悔莫及.但是后悔是没用的,现在趁还有余力,把这本书好好看一遍,并通过C#通通实 ...
- 剑指Offer-【面试题02:实现Singleton 模式——七种实现方式】
题目:设计一个类,我们只能生成该类的一个实例 package com.cxz.demo02; /** * Created by CXZ on 2016/9/13. */ public class Si ...
随机推荐
- Fizz-Buzz-Whizz
Fizz-Buzz-Whizz ThoughtWorks测试 问题描述: 1. 你首先说出三个不同的特殊数,要求必须是个位数,比如3.5.7. 2. 让所有学生拍成一队,然后按顺序报数. 3. 学生报 ...
- poj3414--Pots(bfs,记录路径)
Pots Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10149 Accepted: 4275 Special J ...
- Android Studio简单设置(转)
Android Studio 简单设置 界面设置 默认的 Android Studio 为灰色界面,可以选择使用炫酷的黑色界面.Settings --> Appearance --> Th ...
- metaq spring
spring metaq spring bean 配置 <bean id="sessionFactory" class="com.taobao.metamorpho ...
- NSIS:禁止选择安装路径和编辑安装目录
原文 NSIS:禁止选择安装路径和编辑安装目录 如果你想在安装包中禁止用户选择安装路径和编辑安装目录,有两种方式. 第一种:注释或删除安装目录选择页面 1 ;!insertmacro MUI_PA ...
- (大数据工程师学习路径)第四步 SQL基础课程----修改和删除
一.准备 在正式开始本内容之前,需要先从github下载相关代码.该代码可以新建两个数据库,分别名为test_01和mysql_shiyan ,并在mysql_shiyan数据库中建4个表(depar ...
- Codeforces Round #257 (Div. 2/A)/Codeforces450A_Jzzhu and Children
解题报告 没什么好说的,大于m的往后面放,,,re了一次,,, #include <iostream> #include <cstdio> #include <cstri ...
- hdu4705 Y 简单树形DP 2013多校训练第十场 J题
题意:求一棵树中不在一条链中的三个点的对数. 转化一下,用总对数减去在一条链上的三点对数即可. 考虑经过根节点,然后可能是不同的子树中各选一个:或者是子树中选一个,然后当前节点为根的子树以外的节点选一 ...
- 使用iframe从网页调起移动端应用
比如想在网页中调起支付宝,我们可以创建一个iframe,src为: alipayqr://platformapi/startapp?saId=10000007&clientVersion=3. ...
- linux 下 apache启动、停止、重启命令
原文:linux 下 apache启动.停止.重启命令 基本的操作方法: 本文假设你的apahce安装目录为/usr/local/apache2,这些方法适合任何情况 apahce启动命令: 推荐/u ...