单例模式

来源:互联网 发布:医院网络咨询培训 编辑:程序博客网 时间:2024/06/07 14:32

http://www.cnblogs.com/V1haoge/p/6510196.html

publicclass Singleton {

   

    publicstaticvoid main(String[] args)

    {

       //创建Singleton对象不能通过构造器,只能通过getInstance方法

       Singleton s1 = Singleton.getInstance();

       Singleton s2 = Singleton.getInstance();

       //将输出true

       System.out.println(s1 == s2);

    }

   

    //使用一个变量来缓存曾经创建的实例

    privatestatic Singleton instance;

    //将构造器使用private修饰,隐藏该构造器

    private Singleton(){

       System.out.println("Singleton被构造!");

    }

   

    //提供一个静态方法,用于返回Singleton实例

    //该方法可以加入自定义的控制,保证只产生一个Singleton对象

    publicstatic Singleton getInstance()

    {

       //如果instancenull,表明还不曾创建Singleton对象

       //如果instance不为null,则表明已经创建了Singleton对象,将不会执行该方法

       if (instance == null)

       {

           //创建一个Singleton对象,并将其缓存起来

           instance = new Singleton();

       }

       returninstance;

    }

}

单例模式主要有如下两个优势:

1)      减少创建Java实例所带来的系统开销

2)      便于系统跟踪单个Java实例的生命周期、实例状态等

1、常见的单例模式有两种创建方式:所谓饿懒汉式与饿汉式

(1)懒汉式

  何为懒?顾名思义,就是不做事,这里也是同义,懒汉式就是不在系统加载时就创建类的单例,而是在第一次使用实例的时候再创建。

详见下方代码示例:

复制代码
 1 public class LHanDanli { 2     //定义一个私有类变量来存放单例,私有的目的是指外部无法直接获取这个变量,而要使用提供的公共方法来获取 3     private static LHanDanli dl = null; 4     //定义私有构造器,表示只在类内部使用,亦指单例的实例只能在单例类内部创建 5     private LHanDanli(){} 6     //定义一个公共的公开的方法来返回该类的实例,由于是懒汉式,需要在第一次使用时生成实例,所以为了线程安全,使用synchronized关键字来确保只会生成单例 7     public static synchronized LHanDanli getInstance(){ 8         if(dl == null){ 9             dl = new LHanDanli();10         }11         return dl;12     }13 }
复制代码

(2)饿汉式

  又何为饿?饿者,饥不择食;但凡有食,必急食之。此处同义:在加载类的时候就会创建类的单例,并保存在类中。

详见下方代码示例:

复制代码
 1 public class EHanDanli { 2     //此处定义类变量实例并直接实例化,在类加载的时候就完成了实例化并保存在类中 3     private static EHanDanli dl = new EHanDanli(); 4     //定义无参构造器,用于单例实例 5     private EHanDanli(){} 6     //定义公开方法,返回已创建的单例 7     public static EHanDanli getInstance(){ 8         return dl; 9     }10 }
复制代码

3、类级内部类方式

  饿汉式会占用较多的空间,因为其在类加载时就会完成实例化,而懒汉式又存在执行速率慢的情况,双重加锁机制呢?又有执行效率差的毛病,有没有一种完美的方式可以规避这些毛病呢?

  貌似有的,就是使用类级内部类结合多线程默认同步锁,同时实现延迟加载和线程安全。

 

复制代码
1 public class ClassInnerClassDanli {2     public static class DanliHolder{3         private static ClassInnerClassDanli dl = new ClassInnerClassDanli();4     }5     private ClassInnerClassDanli(){}6     public static ClassInnerClassDanli getInstance(){7         return DanliHolder.dl;8     }9 }
复制代码