[学习笔记]设计模式[4]-{单件模式}

来源:互联网 发布:linux集成开发环境 编辑:程序博客网 时间:2024/05/21 09:41

设计模式

在一个大型系统中,不可避免的会出现只能存在一个的类,比如线程池,对话框,配置设置等等,如果参与开发系统的人不止一个(这是很常见的场景),就无法保证不会有两个人同时在自己的代码里实例化了这个只能存在一个的类。
下面介绍的单件模式(单例模式)就可以在根源(只能存在一个的类)上避免出现上面的问题。
首先介绍一下单件模式的定义:

单件模式

确保一个类只有一个实例,并提供一个全局访问点。
单件模式有很多种实现的形式,下面从最简单的实现说起。

经典单件模式

如果要让别人不随便实例化自己,很明显需要把自己的构造器声明为私有的,然后提供给外部的是一个经过处理的“构造方法”。
下面是经典单件模式的实现代码:

public class Singleton{    private  static Singleton singleton;    private Singleton(){}    public static Singleton getInstance(){        if (singleton == null){            singleton = new Singleton();        }        return singleton;    }}

当别的类需要使用Singleton类时,只需要调用getInstance()方法,就可以获得一个Singleton类,而只有在第一个调用者会让这个类实例化,之后的调用者都是调用的之前实例化过的类。
通过这种方法,就可以“保证”Singleton在使用的时候只会存在一个实例。
但是,这是在没有考虑多线程的情况下才能好用的方法,如果有多个线程同时调用了getInstance()方法,可能就会产生多个Singleton类,这样就会出现单件类不单件的情况。
下面的几种模式都是为了应对这种情况而产生的:

synchronized关键字同步getInstance()方法。

对上面的代码加上一个关键字,就可以避免多线程的问题:

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

既然多线程在同时调用getInstance()方法时,可能会出现同时判断singleton == null的情况,那我们只需要加上synchronized关键字,让这个方法在多线程的过程中只能一次执行一个。
但是这样做会导致一个新的问题:效率变低。很明显的是,我们只需要在第一次调用的时候保证没有两个线程同时进入这个方法就可以保证正常工作,而加上synchronized后,每次调用都会要同步等待,这样会很浪费时间!

“急切”创建实例

如果对singleton的判空会导致多线程的问题,那我们干脆直接在程序启动的时候就实例化这个对象!

public class Singleton{    private  static Singleton singleton = new Singleton();    private Singleton(){}    public static synchronized Singleton getInstance(){        return singleton;    }

通过这个方法,我们在JVM加载这个类的时候对这个类进行实例化,那么我们就不需要关心多线程冲突的问题了。但是这样的操作会导致程序的启动的时候负担太重,如果有多个这样的单例或者有没有调用过的单例,这样的方法就会浪费空间和时间。

“双重检查加锁”方法

使用volatile关键字,确保变量被处理的时候,多线程可以正确的工作。
“双重检查加锁”方法实现如下:

public class Singleton {    private volatile static Singleton singleton;    private Singleton(){}    public static Singleton getInstance(){        if(singleton == null){            synchronized(Singleton.class){                if(singleton == null){                    singleton = new Singleton();                }            }        }        return singleton;    }}

第一个判断为真后,会再次进入一个同步的判断,这样即使多个线程同时进入了第一个判断,也会同步地进行下一个判断,如果为真则会进行对象的实例化。

0 0
原创粉丝点击