Java编程开发设计模式之--单例模式(Singleton)

        单例模式最初的定义出现于《设计模式》(艾迪生维斯理, 1994):“保证一个类仅有一个实例,并提供一个访问它的全局访问点。” Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”

        单例对象(Singleton)是一种使用频率较高的设计模式。在JAVA APP中单例能确保JVM中只有一个存在的实例。这种设计思想有以下一些利点:

1. 一些常用的类的频繁创建,且系统开销较大的类,降低其对系统的开销。

2. 限制了new 操作符的使用,降低内存使用次数,减轻系统垃圾回收的压力。

3.  对于某些核心操作,例如数据存储,付费交易,单实例才能保证对整个流程的准确,完全的控制。

        单例模式的基本是,私有构造方法,让类不可被外部实例化 ,并持有一个私有(不可以被外部引用)的静态实例,只提供一个公有的静态方法给外部调用,用于实例创建。

        下面是一个简单的单例类

        代码:

public class DataBserHelp {
    private static DataBserHelp dataBserHelp = null;

    private DataBserHelp() {
    }

    public static DataBserHelp getInstance() {
        if (null == dataBserHelp) {
            dataBserHelp = new DataBserHelp();
        }
        return dataBserHelp;
    }
}
测试类使用:
public class WorkClass {
    public void test()
    {
        DataBserHelp dataBserHelp = DataBserHelp.getInstance();
   dataBserHelp.query("select * from table where ...");
}}

        在不考虑线程安全的情况下,这样的单例完全可以满足需求。但如果我们把它放入多线程的环境下,肯定就会出现问题了。解决这个问题的方法,首先我们会想到对getInstance方法加同步锁即synchronized关键字。

        Code:

public static synchronized DataBserHelp getInstance() {
    if (null == dataBserHelp) {
        dataBserHelp = new DataBserHelp();
    }
    return dataBserHelp;
}
synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了,所以,这个地方需要继续改进
        Code:

public class DataBserHelp {
    private static DataBserHelp dataBserHelp = null;

    private DataBserHelp() {
    }

    public static DataBserHelp getInstance() {
        if (null == dataBserHelp) {
            syncInit();
        }
        return dataBserHelp;
    }

    private static synchronized void syncInit() {
        if (null == dataBserHelp) {
            dataBserHelp = new DataBserHelp();
        }
    }
}

   整个程序只需要创建一次实例,所以性能上也不会有什么影响。以上代码基本可以说解决了单例模式的线程安全。
   单例模式中一般还会有一种情况需要注意,常言道优点也即缺点,单实例对于有需求属性更新时,是个问题,这里引出影子实例的概念,即直接生成另一个单例对象实例,这个新生成的单例对象实例将从数据库或文件中读取最新的配置信息;然后将这些配置信息直接赋值给旧单例对象的属性。

Code如下
public class DataBserHelp {
    private static DataBserHelp dataBserHelp = null;

    public Vector getmProperties() {
        return mProperties;
    }

    public void updateProperties() {
        DataBserHelp shadow = new DataBserHelp();//新生成的对象将从数据库或者文件中读取最新的配置信息,再赋值给旧单例对象
        mProperties = shadow.getmProperties();
    }

    private Vector mProperties = null;

    private DataBserHelp() {
        mProperties = new Vector();
        if (null == dataBserHelp) {
            mProperties.add(0, "1.0");
        } else {
            mProperties.add(0, "2.0");
        }
    }

    public static DataBserHelp getInstance() {
        if (null == dataBserHelp) {
            syncInit();
        }
        return dataBserHelp;
    }

    private static synchronized void syncInit() {
        if (null == dataBserHelp) {
            dataBserHelp = new DataBserHelp();
        }
    }
}


 测试类代码:
public class WorkClass {
    public void test()
    {
        DataBserHelp dataBserHelp = DataBserHelp.getInstance();
        System.out.println("dataBserHelp.getmProperties().get(0)=="+dataBserHelp.getmProperties().get(0));
        dataBserHelp.updateProperties();
        System.out.println("dataBserHelp.getmProperties().get(0)=="+dataBserHelp.getmProperties().get(0));
    }
}
输出:
I/System.out: dataBserHelp.getmProperties().get(0)==1.0
     I/System.out: dataBserHelp.getmProperties().get(0)==2.0


结语:单例模式简单易懂,但是实际项目中的运用还是有一定的深度的,synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用,可能并不是整个对象或某个过过程都需要锁。影子实例的运用切实解决了单例对象的属性更新需求。

与单例类相似功能的静态类与之有什么区别?总结如下:

1. 静态类不能实现接口,单例可以。

2. 静态类一般首次加载初始化,而单例可以延迟初始化,这点对于提升性能有帮助。

3. 单例类可以被继承,方法可覆写,静态类方法都是static的,无法覆写。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章