设计模式:单例模式

来源:互联网 发布:二维图形变换矩阵 编辑:程序博客网 时间:2024/05/16 12:26

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

Creational 模式

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

  • Simple Factory 模式
  • Abstract Factory 模式
  • Builder 模式
  • Factory Method 模式
  • Prototype 模式
  • Singleton 模式
  • Registry of Singleton 模式

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

懒汉式和饿汉式

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

//懒汉式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 !

0 0