每天一个设计模式-4 单例模式(Singleton)

1.实际生活的例子

有一天,你的自行车的某个螺丝钉松了,修车铺离你家比较远,而附近的五金店有卖扳手;因此,你决定去五金店买一个扳手,自己把螺丝钉固定紧。不一会儿,自行车就被你修好了;首先,这个扳手你不会扔掉,下次用的时候直接找出来就用了。好,今天的主题出来了“单例模式”。

2.与变成关联

在上面的例子中,能找出几个关键字:“买一个扳手”,“螺丝钉固定紧”,“不会扔掉扳手”,“下次用直接找出来”。我们结合标题和这几个关键字好好理解一下:

买一个扳手:创建一个实例。

螺丝钉固定紧:这个实例的功能。

不会扔掉扳手:保存这个实例。

下次用直接找出来:从保存的实例中取出来。

ok,今天我们学习的重点就是这些。

3.单例模式的定义

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

分析:“仅有一个实例”,如何做到仅有一个实例呢?我们知道,java中实例的生成需要通过构造函数,外部通过这个构造函数生成对应的对象,那么如果我们把构造函数私有化不就可以做到外部无法实例化该对象了吗;但是,该如何调用这个实例的方法呢?我们可以在该类内部执行构造函数,并将构造后的对象保存在该类的属性中,并提供一个全局的访问点供外部调用,因为不能在外部生成该类实例,所以这个全局访问点被static修饰,这样我们就可以直接通过类访问这个方法。

好的!!下面放出代码。

4.类图

UML类图讲解:http://blog.csdn.net/tianhai110/article/details/6339565

4.代码

实现单利模式,有两种方法,一种是懒汉式,另一种是饿汉式,最终都是单例模式,只是实现方式略有不同。下面先放出代码:

懒汉式实现:

public class BanShou {

    private static BanShou savedBanShou=null;

    public void finalize() throws Throwable {

    }

    private BanShou(){
        System.out.println("我买了一个扳手");
    }

    public static BanShou getInstance(){
        if(savedBanShou==null){
            savedBanShou = new BanShou();
            return savedBanShou;
        }
        System.out.println("嘿,我找到了我以前买的扳手,这下可以不用再买了");
        return savedBanShou;
    }

    public void repaire(){
        System.out.println("拧紧螺丝钉");
    }

}

扳手类

public class Client {

    public static void main(String[] args) {
        for(int i=0;i<3;i++){
            System.out.println("这是第"+i+"次用到了扳手");
            BanShou.getInstance().repaire();;
        }
    }
}

客户类

饿汉式实现:

public class BanShou2 {
    private static BanShou2 savedBanShou=new BanShou2();

    public void finalize() throws Throwable {

    }

    private BanShou2(){
        System.out.println("我买了一个扳手");
    }

    public static BanShou2 getInstance(){
            return savedBanShou;
    }

    public void repaire(){
        System.out.println("拧紧螺丝钉");
    }
}

饿汉式扳手类

测试结果:

这是第0次用到了扳手
我买了一个扳手
拧紧螺丝钉
这是第1次用到了扳手
嘿,我找到了我以前买的扳手,这下可以不用再买了
拧紧螺丝钉
这是第2次用到了扳手
嘿,我找到了我以前买的扳手,这下可以不用再买了
拧紧螺丝钉

5.模式讲解

在上面的代码中看到单例模式可以用两种方式实现,那么他们的区别是什么呢?首先,先从名称上理解一下,懒汉式:因为很懒,所以做事都是拖到最后,不得不做时才去做;饿汉式:因为很饿,所以做事很急。体会一下应该就能懂了。↓↓↓↓懒汉式

public static BanShou getInstance(){
        if(savedBanShou==null){
            savedBanShou = new BanShou();
            return savedBanShou;
        }
        System.out.println("嘿,我找到了我以前买的扳手,这下可以不用再买了");
        return savedBanShou;
    }

获取实例时,先去判断是否为空,如果为空,再去创建(拖到最后,不得不做时才去做)。

↓↓↓↓饿汉式

private static BanShou2 savedBanShou=new BanShou2();
public static  BanShou2 getInstance(){
            return savedBanShou;
    }

获取实例前就已经创建好了,无论你用不用(做事很急)。

懒汉式实现方式中也涉及了延迟加载的思想(LazyLoad),通俗的说就是:一开始时不要加载资源或数据,一直等,等到马上就要使用这个资源或者数据了,躲不过了才去加载,这在实际开发中是一种常见的思想,尽可能的节约资源。

饿汉式和懒汉式的实现还体现了缓存的思想:当某个文件,或数据库数据被频繁使用,如果每次都从文件或数据库中读取,速度会变得很慢,如果把这些数据放到内存中,每次取数据时都从缓存中提取,那么速度便会得到很大的提升。

private static BanShou2 savedBanShou=new BanShou2();
private static BanShou savedBanShou=null;

这两行代码就是起到了缓存的作用。

6.单利模式的线程问题

懒汉式实现方式是线程不安全的,比如:

如何解决呢?想让懒汉式变成线程安全的,最简单的办法就是用synchronized

public static synchronized BanShou getInstance()

但这样做会降低系统性能,因为线程互斥,每次都要等待。

有一种双重加锁方式可以解决这个问题。双重加锁方式就是:

并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建实例,这是第二重检查。这样,就只需要同步一次,从而减少了多次在同步情况下进行判断所浪费的时间。双重加锁机制的实现会使用一个关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。

但这种方式用到了volatile,它会屏蔽掉虚拟机中的一些必要的代码优化,所以运行效率不是很高,下面推荐一个更好的单例实现方式:

直接放出源代码吧,也涉及一些其他的基础知识,这里就不写了,毕竟这么晚了;今天比较忙,所以现在才更新。不好意了。

更好的单例模式实现源代码:

public class Singleton {
    //这部分只有被调用到时,才会被装载,既线程安全,有延迟加载
    private static class SingletonHolder{
        private static Singleton instance = new Singleton();
    }
    private Singleton(){

    }
    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }
}

7.总结

实现单例模式,就必须将构造器私有化,在类内部实例化,并提供全局的访问点,从而达到控制实例的数目的目的

-------博主写博客不容易,转载请注明出处,谢谢:http://www.cnblogs.com/xiemubg/p/5954949.html

每天一个设计模式-4 单例模式(Singleton)的更多相关文章

  1. 设计模式之单例模式——Singleton

                        设计模式之单例模式--Singleton 设计意图: 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有 ...

  2. 设计模式(4) -- 单例模式(Singleton)

    设计模式(4)  -- 单例模式(Singleton) 试想一个读取配置文件的需求,创建完读取类后通过New一个类的实例来读取配置文件的内容,在系统运行期间,系统中会存在很多个该类的实例对象,也就是说 ...

  3. 乐在其中设计模式(C#) - 单例模式(Singleton Pattern)

    原文:乐在其中设计模式(C#) - 单例模式(Singleton Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 单例模式(Singleton Pattern) 作者:weba ...

  4. 【设计模式】单例模式-Singleton

    [设计模式]单例模式-SingletonEnsure a class has only one instance, and provide a global point to access of it ...

  5. 设计模式之 -- 单例模式(Singleton)

    单例模式是一种常用的软件设计模式,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问. 使用说明 1.使用时机  在某些系统中某些对象最多只能存在一个,例如Windows中只能打开一个 ...

  6. 设计模式之——单例模式(Singleton)的常见应用场景

    单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此 ...

  7. 设计模式之单例模式(Singleton Pattern)

    单例模式 单例模式(Singleton Pattern)在java中算是最常用的设计模式之一,主要用于控制控制类实例的数量,防止外部实例化或者修改.单例模式在某些场景下可以提高系统运行效率.实现中的主 ...

  8. 设计模式一: 单例模式(Singleton)

    简介 单例模式是属于创建型模式的一种(另外两种分别是结构型模式,行为型模式).是设计模式中最为简单的一种. 英文单词Singleton的数学含义是"有且仅有一个元素的集合". 从实 ...

  9. 设计模式之——单例模式(Singleton)的常见应用场景(转):

    单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此 ...

随机推荐

  1. java统计字符串单词的个数

    在一些项目中可能需要对一段字符串中的单词进行统计,我在这里写了一个简单的demo,有需要的同学可以拿去看一下. 本人没怎么写个播客,如果有啥说的不对的地方,你来打我啊 不说废话了直接贴代码: 实现代码 ...

  2. Highcharts中国地图热力图

    最近有个项目需要将MC销量按大陆各省统计,并以中国地图人力图效果显示.由于项目一直使用Highcharts进行图表的统计,故采用Highmaps来实现. 效果如下: 1)中国各个省.直辖市.自治区: ...

  3. Angular2 Hello World 之 2.0

    最近angular2正式版发布了,现在就趁热接着记录一下2.0版的Hello World.据说由RC6升级到2.0代码改动不是很大,在写的时候也感觉改动不是很大,这次记录还是以asp.net core ...

  4. 简历生成平台项目开发-STEP1问卷设计

    周五课程结束完后,小组建立QQ群和微信群,着手讨论项目问题.一开始的大概想法:就业信息平台,收集企业招聘信息和就业生资料,提供给学生和企业的校企对接平台.后来发现群里谭卓同学也有个相关的思路,经过商量 ...

  5. 包含LOB_Data列的表删除大量数据后表及数据库文件的收缩

    最近有一张表(内含varchar(max)字段),占用空间达到240G,删除历史数据后几十万条后,空间并未得到释放. 然后用DBCC CLEANTABLE(0,tb_name,100)来释放删除记录后 ...

  6. exportfs 入门/ 错误

    exportfs -uv 不能卸载, exportfs -au 才可以 ================================================================ ...

  7. JavaScript随笔3

    1.获取非行间css if(oDiv.currentStyle){ alert(oDiv.currentStyle.width); }else{ alert(oDiv.getComputedStyle ...

  8. MSSQLSERVER添加c# clr程序集的使用方法

    前言 MSSQLSERVER提供程序集,无疑可以让编程人员更加便捷的操作数据库数据,比如c#写的函数,可以在数据库当作sql的函数使用,你想想他对不熟悉数据库的程序员来说是有多么的嗨.这么好的机制,大 ...

  9. PostCSS深入学习: PostCSS和Sass、Stylus或LESS一起使用

    如果你喜欢使用PostCSS,但又不想抛弃你最喜欢的预处理器.不用担心,你不需要作出二选一的选择,你可以把PostCSS和预处理器(Sass.Stylus或LESS)结合起来使用. 有几个PostCS ...

  10. 帮我做个APP,给你20万,做不做?

    一.为什么要写这篇文章 前段时间,有个辞职 创业的同事(做法务的)  问我 开发一个 新闻类的APP要多少钱,产品.UI.接口.后台管理页  他们啥都没有,想全部外包. 我 并没有在外包公司做过,也没 ...