你真的了解Singeton吗?

原创 2016年09月05日 20:13:26

时代在进步,随着人们对编程语言理解程度的不断加深,设计模式也在不断进步。笔者对Singleton模式的理解,也经历了不断加深的一个过程。今天我们就来聊聊Java语言最常用的设计模式之一——单例模式(Singleton)。

1. 什么是Singleton

Singleton的正式提出,自然来自GoF的《设计模式》。单例模式中的“单例”通常用来代表那些本质上具有唯一性的系统组件(或者叫做资源)。比如文件系统、资源管理器等等。

GoF:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

对于Java语言,需要考虑的问题就更复杂一点,主要是Singleton定义的范围。不说明范围的Singleton就是在耍流氓

1、对于Java,一般单实例的范围应该时JVM内唯一。

2、每个类加载器(ClassLoader)都能够加载同一个类,使得在同一JVM中存在多个实例。所以在多加载器情形,应当首先考虑单实例的应用范围。

对于Singleton的各种书写方式及其分析,有一篇文章比较全面:http://www.cnblogs.com/520yang/articles/4535096.html

2. 为什么使用Singleton

本段中,如无特殊说明,默认Singleton范围是本JVM,只有一个ClassLoader。

Singleton有一个“强力竞争者”:静态变量+静态变量的类。很多情况下它们能够实现同样的功能,所以我们必须弄明白Singleton独有的优势。

我们先看一下Singleton的基本形式:

public class SingletonBasic {
    // The Singleton factory part
    private static SingletonBasic instance;
    public static SingletonBasic getInstance(){
        if (instance == null){
            instance = new SingletonBasic();
        }
        return instance;
    }
    // The Singleton provided functions
    private Object var1;
    private Object var2;
    private SingletonBasic(){}

    public void doSomething(){System.out.print(var1);}
    public int returnSomething(){
        return 0;
    }
}

通过观察,我们可以从这个基本形式,总结一下Singleton的特点。这种写法虽然在工程代码中不建议,但是作为麻雀解剖却是极好的。

  1. 自己负责自身实例的创建和维护。
  2. 通过实例对外提供功能。
  3. 有延迟加载的效果。
  4. 扩展为N实例模式时,外部不感知。

简单说,Singleton就是工厂+单态。相对于如下的静态方式,单例模式的特点,似乎大部分都有问题了。

public class SingleStatic {
    private static Object var1 = new Object();
    private static Object var2 = new Object();

    private SingleStatic(){
        throw new Exception();
    }

    public static void doSomething(){
        System.out.print(var1);
    }
    public static int returnSomething(){
        return 0;
    }
}

对于上面的写法,

第一,根本就不需要创建实例,而且,不允许外部调用构造函数。这方面比单例模式更加安全(当然单例模式还有更安全的枚举写法)。

第二,所有功能均具备。差别仅仅在于延迟加载,以及可能扩展为N实例的需求。

对于N实例的扩展需求,这本质上是工厂模式的优势所在,算不得单例模式的好处。那么,使用Java单例模式的好处,就只剩下了延迟加载这一个。然而延迟加载是否真的那么重要?以至于要用单独的一个模式来支持它?

面对这个明显的不合理,经过“慎重思考”,我终于又想到一个理由:不需要一直驻留内存,但最多只能有一个实例的情况。

然而,不需要一直驻留内存,则需要使用完后就把内存回收,但是我们的Singleton经典写法,实例却是static的,这意味着只要实例化一次,就永远无法垃圾回收!这是怎么话说的?笔者瞬间凌乱了……

3. 进一步分析

经过上述分析,我们看到,Singleton的应用场景,只有三个:

  1. 需要延迟加载的特性。比如,要加快系统启动速度,用Singleton将服务包装,避免大量数据在类初始化时就加载进来。

  2. 不需要一直常驻内存。这时使用Singleton,由于其实例是static的,所以必须通过显式的方法,在不再需要的时候,将实例注销。

  3. 可能会扩展为对象池。

4. 使用Singleton的正确姿势

A. 多线程

通过上述分析,我们发现,Singleton天生就要应对多线程的场景。所以,线程安全肯定是必须考虑的因素。我们在网上一搜,多数介绍Singleton相关的文章都是把多线程放在首位,而且对线程安全的写法的分析也是最早出现的。现在我们应该明白为什么会如此了。

在所有线程安全的写法中,静态内部类和枚举是被人们所推荐的。尤其是枚举,更是得到了一些大牛的支持。

B. 测试

然而,Singleton模式还有另外一个扰不过去的问题,那就是测试困难。这个难题如何解决呢?

其实单例模式对外提供的是一组服务。之所以测试困难,是因为这些服务依赖于内部的状态,而内部的状态值在初始化时又依赖于其它不方便模拟的资源。下边的代码是一种解决思路:

public enum XXService{
    service;
    private int value;
    XXService(){
        DataProvider provider = Factory.getProvider();
        value = provider.provide();
    }
    public int getValue(){return value;}
}
interface DataProvider{
    int provide();
}
// 注意这里是包权限
class Factory {
    private static instance = new DefautProvider();
    static DataProvider getProvider(){
        return instance;
    }
    static void set(DataProvider userDefine){
        instance = userDefine;
    }
}

C. 需要注销的情况

在这种情况下,单实例往往就不能把工厂与自身结合到一起了。于是工厂独立出来后,形成一个Registry。单实例在初始化时,把自己注册到Registry中;一旦不再需要,便可以注销。

如果硬要使用经典模式,也不是不可以,只是需要增加一个delete函数来消除静态实例。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

浅谈 指针-你真的了解指针吗?

指针 关键字:另类,新奇 最近在学习的过程中,产生了疑问,也得到了解决,对于指针的了解又上了一个层面 -----下面,我就对 (平日里以为很了解的指针)来发表一下我的一个另类的观点  ...

你真的了解javascript吗?(一)

当初以为不过是一些小题目,结果做到怀疑人生,都要怀疑可能我javascript白学了。读者可以去试试。 不多说,直接上题: 第一题 ["1", "2", "3"].map(parseIn...

Android提醒微技巧,你真的了解Dialog、Toast和Snackbar吗?

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/51336415 本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微...

你真的了解DispatcherServlet的url-pattern配置吗?

前言对于springmvc中前端控制器url-pattern配置, 看了很多博客, 发现好多人理解都是错误, 并不清楚会拦截什么路径的请求, 有点小的细节并不被大家所关注.

使用这些技巧,看看谷歌是否真的了解你?

20160407 使用这些技巧,你能找出多少关于谷歌是否真的了解你? 你曾经是不是对你访问一个网站的时候,看到你喜欢的手表,并且你迫切的想要的时候,却跳出了广告感到很吃惊?这就是谷歌的力量。谷歌也...

使用CSS确定HTML中的断句格式——你真的了解word-wrap和word-break的区别吗

你真的了解word-wrap和word-break的区别吗? 这两个东西是什么,我相信至今还有很多人搞不清,只会死记硬背的写一个word-wrap:break-word;word-break:bre...
  • r5014
  • r5014
  • 2017-06-08 10:03
  • 146

android权限机制,你真的了解么

android权限机制,你真的了解么一、Android的权限机制 Android是目前最流行的智能手机软件平台之一,在智能移动终端如火如荼发展的同时,其安全态势也日益严峻。有调查表明,恶意软件的数...

Java技术——你真的了解String类的intern()方法吗

0.引言 什么都先不说,先看下面这个引入的例子: [java] view plain copy String str1 = new String("SEU")+ new Stri...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)