文档章节

【23种设计模式之一】单例设计模式(翻译)

敲代码猥琐男
 敲代码猥琐男
发布于 2015/01/13 22:47
字数 2060
阅读 639
收藏 7

引言:

    这一系列文章,翻译自网络上的文章,不过中间会夹杂着个人的理解,非原创,不过中文应该算是原创。

    下面介绍,使用设计模式的一些好处:

    1、设计模式是已经在工业生产中使用的,用于解决特定问题的标准方法,如果你在遇到类似问题的时候,能参考相应的设计,会节省你很多的时间。

    2、设计模式,往往能提高代码的重用性,会减少你的开发时间。

    3、既然大家都知道设计模式,包括从你的类的命名上面,类的使用上面,大家都很清楚的知道相应类的具体功能,就像每个人都约定好的那样。

 分类:

    java设计模式分为3大类:

    1、对象创建

    2、结构

    3、行为

对象创建设计模式的定义

    1、在特定的问题场景中,创建设计模式会合理的根据特定的问题创建对象。因为对象的创建可能会很复杂,会增加不必要的复杂性,创建设计模式以不同的创建方法解决了这些复杂性。

对象创建设计模式包含的范围:

    1、单例

    2、工厂

    3、抽象工厂

    4、建造者

    5、原型

    本节会讲一下,对象创建中的单例设计模式。

    单例设计模式,大部分人第一印象感觉很简单,看完这篇博客,我想你就不会这么认为啦,不同的开发者对于以何种方式实现单例设计模式是有争议的,本文尽可能的把目前实现单例的方法概括出来,并给出最佳实战的建议。

单例模式的定义:

    单例模式是一种创建对象实例的设计模式,在创建对象的过程中,他会保证,在一个java虚拟机里面只有一个对象实例,同时单例设计模式,必须提供一个给外部访问该唯一对象的入口。

单例模式的应用场景:

    日志、驱动对象、缓存、线程池等等,当然设计模式不是单一存在的,其它设计模式中也会使用单例设计模式来完成一些事情,比如:抽象工厂,建造者,原型,门面等。同时在java核心包里面也有其身影,比如java.lang.runtime.

单例模式的实现方法的共性:

    1、提供私有的构造函数,防止外部类直接初始化该对象

    2、提供私有的静态变量,当然要是该类的对象实例,唯一的对象实例。

    3、public的静态方法,这就是上面说的,提供给外部类获取该类对象的唯一入口。

接下来,我们会以不同的方法,来实现单例设计模式。

【A】饥饿实现

    饥饿实现就是,等不急,当类被classloader加载的时候就初始化了该对象,这种实现有个弊端就是,当client不使用该类实例就浪费啦,不过我个人觉得,这种情况不存在,你不用他写他做什么呢?代码测试要有覆盖率的,测试天天在你后面催着喊你把他删掉。

public class EagerInitializedSingleton 
{
     private static final EagerInitializedSingleton instance = new
     EagerInitializedSingleton();
    //private constructor to avoid client applications to use constructor
     private EagerInitializedSingleton(){}
     public static EagerInitializedSingleton getInstance()
     {
        return instance;
     }
}

    如果你的单例对象在创建的时候不使用过多的资源,这种方法是可行的。但是大部分的时候,单例对象创建的时候会加载很多的资源文件,比如File system,数据库连接等等。我们应该避免在客户端调用getInstance方法之前创建这个对象,但是这种方法无法提供异常的捕获,异常的抛出,可能在创建对象的时候。

【B】静态块的实现方式

    静态块的实现方式和上面的实现方式差不多,但是静态块的实现,可以处理异常。代码如下:

public class StaticBlockSingleton
{
    private static StaticBlockSingleton instance;
    private StaticBlockSingleton(){}
    //static block initialization for exception handling
    static
    {
        try{
            instance = new StaticBlockSingleton();
           }catch(Exception e)
           {
                throw new RuntimeException("Exception occured in creating singleton instance");
           }
    }
    public static StaticBlockSingleton getInstance()
    {
        return instance;
    }
}

    和饥饿的实现方式一样,当类被classloader加载的时候就初始化了该对象。

【C】延迟创建

    顾名思义,就是需要的时候再去创建。

public class LazyInitializedSingleton 
{
    private static LazyInitializedSingleton instance;
    private LazyInitializedSingleton(){} 
    public static LazyInitializedSingleton getInstance()
    {
        if(instance == null)
        {
            instance = new LazyInitializedSingleton();
        }
        return instance;
    }
}

    上面这种实现方法,在单线程的环境下是工作良好的,但是,在多线程并发创建对象的时候会出现问题,简单的分析下原因,考虑多线程并发安全的时候,首先要找到共享点,就是共享的对象,然后想象各种执行顺序,你会发现instance这个地方就是共享点,当多线程执行的时候,有可能会创建多个对象,所以该方法不能保证单例实现。

【D】线程安全的创建

    为了解决多线程并发创建对象的问题,我们引入Synchronized关键字,这样的话,同一时刻,只有一个对象能访问getInstance方法。

public class ThreadSafeSingleton
{
    private static ThreadSafeSingleton instance;
    private ThreadSafeSingleton(){}
    public static synchronized ThreadSafeSingleton getInstance()
    {
        if(instance == null)
        {
            instance = new ThreadSafeSingleton();
        }
        return instance;
    }
}

    这种方式是能防止多并发引起的多对象创建问题,但是写代码嘛,总要追求点东西,你说别人装逼也好,卖弄也罢,总之在某一方面比你好。在多并发中,HashMap和ConcurrentHashMap,你是锁住整个HashMap还是HashMap的一个segment这是有质的区别的,所以改进的代码,只朝着一个方向,那就是降低锁的力度,于是乎,下面的代码使用double check来降低了力度,提高了性能。

public static ThreadSafeSingleton getInstanceUsingDoubleLocking()
{
    if(instance == null)
    {
        synchronized (ThreadSafeSingleton.class) 
        {
            if(instance == null)
            {
                instance = new ThreadSafeSingleton();
            }
        }
    }
    return instance;
}

还有一种实现叫Bill Pugh,java的版本更新变化很快,包括新出的java9,可能名字不是,大家也知道,金融在未来几年是个很火的领域,于是乎java9中集成了货币的api支持,这是我的猜测,哈哈,包括先在的招财宝,铜板街,挖财,据说王福强大神,跳到挖财啦,当然我也是做金融行业的业务,有兴趣的可以留言,据说要招人。这些题外话,但是不无用处哈,java的内存模型会导致上面的几种方法,在很多很多线程出现的时候,会出现问题,于是乎,这个人,也就是Bill Pugh自己实现了一下这种方法:

【E】Bill Pugh实现

public class BillPughSingleton 
{
    private BillPughSingleton(){}
    private static class SingletonHelper
    {
        private static final BillPughSingleton INSTANCE = new
        BillPughSingleton(); 
    }
    public static BillPughSingleton getInstance()
    {
        return SingletonHelper.INSTANCE;
    }
}

看代码发现Bill Pugh是通过私有静态内部类来实现的,当单例对象被classloader加载的时候,SingletonHelper是不会被加载到内存的,除非有对象调用getInstance方法,这是最常用的创建单例对象的方法,因为不需要锁,已经在多个项目中使用了这种方法,简单有效。

【F】Enum实现

public enum EnumSingleton 
{
    INSTANCE;
    public static void doSomething()
    {
        //do something
    }
}

    世界上好人和坏人总是都存在的,单例对象也不例外,总有那么几种方法是搞破坏的,费尽千辛万苦,创建的单例,有可能被破坏的。

    【破坏者1】反射

    【破坏者2】序列化

有破坏办法,就又解决办法,破坏者1的解决办法是ENUM,破坏者2的解决办法是重写readResolve方法。这两部分,你说是和反射有关呢,还是和序列化有关呢,序列化都够我写一篇东西的了。下次再说

                                        poke holes in the abstraction,and it starts leaking.

© 著作权归作者所有

敲代码猥琐男
粉丝 13
博文 28
码字总数 18444
作品 0
杭州
程序员
私信 提问
加载中

评论(2)

旺少
旺少
呵呵
旺少
旺少
java设计模式-- 单例模式

在很久之前,也就是在大二暑假的时候,那时候看马士兵的视频教程中有提到很多的设计模式。 java的设计模式大致可以分为3大类,23种设计模式。 其中,创建型模式有5种:单例模式、建造者模式、...

爱学习的逃课君
2014/11/27
138
0
23种设计模式(1):单例模式

定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 类型:创建类模式 类图: 类图知识点: 1.类图分为三部分,依次是类名、属性、方法 2.以<<开头和以>>结尾的为注释...

LCZ777
2014/07/05
250
0
设计模式1——Singleton设计模式

Singleton单例模式是最简单的设计模式,它的主要作用是保证在程序运行生命周期中,使用了单例模式的类只能有一个实例对象存在。单例模式实现了类似C语言中全局变量的功能,单例模式常用于注册...

小米米儿小
2013/12/05
169
1
Java程序员从笨鸟到菜鸟之(三十三)大话设计模式(三)单例模式

本文来自:曹胜欢博客专栏。转载请注明出处:http://blog.csdn.net/csh624366188 单例模式属于对象创建型模式,其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点。对一些类来说...

长平狐
2012/11/12
162
0
JavaScript 常见设计模式

前言 设计模式,这一话题一直都是程序员谈论的"高端"话题之一。许多程序员从设计模式中学到了设计软件的灵感和解决方案。 有人认为设计模式只在 C++或者 Java 中有用武之地,JavaScript 这种...

YeeWang王大白
03/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何在 Knative 中部署 WebSocket 和 gRPC 服务?

作者 | 冬岛 阿里云容器平台工程师 导读:虽然说 Knative 默认就支持 WebSocket 和 gRPC,但在使用中会发现,有时想要把自己的 WebSocket 或 gRPC 部署到 Knative 中,还是存在各种不顺利。虽...

阿里云官方博客
8分钟前
2
0
人人都可以掌握的正交试验设计测试用例方法

介绍 TamanduaOATs 是测者开发并开源的生成正交计算的pyd(python库)程序(放到python下的dlls目录下) 项目地址:https://github.com/crisschan/TamanduaOATs 开发语言:c++ python调用方法...

测者陈磊
8分钟前
1
0
报表工具跟BI软件到底有什么区别?看完你就懂了

在很多人入门数据分析师或者投身大数据行业的时候,必然会听到的两个词就是“报表工具”和“BI商业智能”。然而很多人并不明白两者的概念和区别,以为报表就是BI,BI就是报表,其实这是相当错...

朕想上头条
17分钟前
2
0
ValidatorException异常处理-PKIX path building failed

Maven下载依赖抛出一个ssl数字证书的异常:PKIX path building failed: SunCertPathBuilderException: unable to find valid certification path to requested target ,记录一下问题的前因后......

liumapp
24分钟前
2
0
JAVA CAS单点登录之三:CAS代理模式演练

前言 JAVA CAS单点登录之一:搭建CAS服务器 JAVA CAS单点登录之二:CAS普通模式1演练 代理模式相相对上一节的普通模式,更加复杂了。但配置起来也会稍微有些差别。所谓难者不会,会者不难。如...

彬彬公子
53分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部