设计模式:单例模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SpeedMe/article/details/41776077

原文地址:http://leihuang.org/2014/12/05/singleton/

Creational 模式

物件的产生需要消耗系统资源,所以如何有效率的产生、管理 与操作物件,一直都是值得讨论的课题, Creational 模式即与物件的建立相关,在这个分类下的模式给出了一些指导原则及设计的方向。下面列举到的全属于Creational 模式


当程序中要求只需要一个单例的时候,那么此时就需要使用单例模式,如果没有这种要求,那么就不需要使用单例模式.

懒汉式和饿汉式

我们先来两个常见的单例模式,懒汉式和饿汉式.

//懒汉式
public class SingletonLazy {
    private static SingletonLazy single = null ;

    private SingletonLazy(){
    }

    synchronized public static SingletonLazy getInstance(){
        if(single == null){
            single = new SingletonLazy() ;
        }
        return single ;
    }   
}
//饿汉式
public class SingletonHunger {
    private static SingletonHunger single = new SingletonHunger() ;

    private SingletonHunger(){
    }

    public static SingletonHunger getInstatnce(){
        return single ;
    }
}

注意,懒汉式单例类实现里对静态工厂方法使用了同步化,以处理多线程环境.

优化版的饿汉式

其实单例模式很简单,但是它涉及到的很多知识就非常复杂了.比如饿汉式虽然解决了多线程安全的问题,不需要使用同步(提高了效率),但是它 却浪费了内存,因为SingletonHunger类装载的时候就初始化了对象,此时我们就可以利用内部类的机制来解决这个问题.

public class SingletonInner {
    private static InnerInstance{
        private static SingletonInner single = new SingletonInner() ;
    }

    private SingletonInner(){
    }

    public static SingletonInner getInstance(){
        return InnerInstance.single ;
    }
}

上面的代码中又涉及到不少知识.

  1. 内部类声明为static的意义:不需要初始化外部内的情况下就能被使用;
  2. 内部类在自己被使用的时候才会被装载,外部内被初始化,但其内部类并未被初始化.详见这里
  3. 类什么时候被加载/类加载时机:第一:生成该类对象的时候,会加载该类及该类的所有父类;第二:访问该类的静态成员的时候;第三:class.forName("类名");

优化版的懒汉式

我们知道懒汉式对于饿汉式的有点在于节约了空间,但其利用同步来解决线程安全性问题,很大程度的降低了程序的效率.

于是我们就想到如何来提高懒汉式的效率,首先它依然还是必须要有同步在里面.

有一种方法就双重检查机制,这个广泛应用在c语言中,但是它在java中却是错误的,如果你上锁的是基本类型的话,是没有问题的,但是你如果锁定的是对象的话就有问题了.但是我们此处是讲单例模式,所以锁的肯定是对象而不是int,long,double等类型数据了.

如下代码是错误的.

public class SingletonLazy01 {
    private static SingletonLazy01 single = null ;
    private SingletonLazy01(){
    }

    public static SingletonLazy01 getInstance(){
        if(single == null){
            synchronized(SingletonLazy01.class){
                if(single == null){
                    single = new SingletonLazy01() ;
                }
            }
        }
        return single ;
    }
}

我们利用volatile关键字

public class SingletonLazy01 {
    private volatile static SingletonLazy01 single = null ;
    private SingletonLazy01(){
    }

    public static SingletonLazy01 getInstance(){
        if(single == null){
            synchronized(SingletonLazy01.class){
                if(single == null){
                    single = new SingletonLazy01() ;
                }
            }
        }
        return single ;
    }
}

至于双重检查问题详见这里--->双重检查锁定与延迟初始化


2014-12-05 19:52:59

Brave,Happy,Thanksgiving !

猜你喜欢

转载自blog.csdn.net/SpeedMe/article/details/41776077