好久没写博客了,以前在CSDN上写过一篇servlet,jsp运行原理,妈的当时计划的很好一周一篇,然后结果就呵呵了,换了新老板已经快3个月了,项目已经稳定线上运行,闲的无事可做,难道这就是程序员追求的生活吗?感觉快废了,现在哪有持续稳定的工作啊?总要找点事做,充实一下自己内心寂寞的灵魂。得了不扯淡了.
本系列文章主要是学习秦小波的<<设计模式之禅>>笔记和总结感悟,便于自己翻看学习和与各位朋友交流。
单例模式定义: 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
相信这个UML类图有经验的程序员都看的懂,通过一个私有的构造方法确保一个应用中只产生一个实例,并且自行实例化这个实例。
单例通用代码:
public class CommonSingleton {
private static CommonSingleton mInstance = new CommonSingleton();
public static CommonSingleton getInstance() {
return mInstance;
}
private CommonSingleton() {
}
public static void sayHello() {
System.out.println("Hello 我是皇帝我独尊");
}
public static void main(String[] args) {
CommonSingleton.getInstance().sayHello();
}
}
单例模式的应用:
单例的特点是在内存中只有一个实例存在,并且常驻内存,如果一个对象需要频繁的创建和销毁时,为了节省内存的开支我们可以用单例,但要注意内存泄漏的可能,比如Android 常见的上下文泄露,
单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
任何设计模式都有它特定的应用场景,单例也有它的不足,只需要根据具体需求选择即可:
单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。
单例模式跟六大设计原则的单一职责原则相冲突,一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中。
单例模式一般不实现接口,扩展性不强.
单例设计模式注意事项:
使用单例首先是需要在特定的场景中,比如生成生成唯一的序列号,缓存一些数据,创建对象需要消耗资源过多访问io操作,数据库操作等,一些app中保存的大量的static 常量可以用单例也可以直接声明为static.
单例使用应该注意高并发的问题,并发场景中,可能就会产生两个实例对象,这就跟我们单例设计的初衷相违背;通常解决方式是在使用syachronized关键字加锁,或者使用同步代码块方式,但都不是最优解;下面列出几种常见的写法:
No1.
private static CommonSingleton mInstance;
public static CommonSingleton getInstance() {
if (mInstance == null) {
mInstance = new CommonSingleton();
}
return mInstance;
}
private CommonSingleton() {
}
public static void sayHello() {
System.out.println("Hello 我是皇帝我独尊");
}
俗称懒汉式,没有线程安全性可言,
No2.
private static CommonSingleton mInstance;
public static synchronized CommonSingleton getInstance() {
if (mInstance == null) {
mInstance = new CommonSingleton();
}
return mInstance;
}
private CommonSingleton() {
}
懒汉式,线程安全的,但是效率极低
No3.
private static CommonSingleton mInstance = new CommonSingleton();
public static CommonSingleton getInstance() {
// if (mInstance == null) {
// mInstance = new CommonSingleton();
// }
return mInstance;
}
private CommonSingleton() {
}
饿汉式,基于classloder机制避免了多线程的同步问题,在类加载时候初始化,
No4。
private static CommonSingleton mInstance ;
static {
mInstance = new CommonSingleton();
}
public static CommonSingleton getInstance() {
// if (mInstance == null) {
// mInstance = new CommonSingleton();
// }
return mInstance;
}
private CommonSingleton() {
}
饿汉式基因变异体,实际上是一样的都是通过类加载时候实例化.
No5.
private static CommonSingleton mInstance;
public static CommonSingleton getInstance() {
if (mInstance == null) {
synchronized (CommonSingleton.class) {
if (mInstance == null) {
mInstance = new CommonSingleton();
}
}
}
return mInstance;
}
private CommonSingleton() {
}
这是一种双重校验式,有效解决线程安全问题,市面上使用的比较多
虽说No5写法校验已经很强了,但是有一种情况的发生,jvm虚拟机可能出现的指令重排序影响双重检查加锁(double-checked locking)的正确性。
我们只需要加一个volatile关键字即可保证指令重排序的正确性。具体原理请看这哥们的介绍的很详细膜拜一下牛人http://www.cnblogs.com/dolphin0520/p/3920373.html
private volatile static CommonSingleton mInstance;
哎我操都4点了,今天就到这吧,不寂寞了休息一下明天继续,