Java单例模式详解

来源:互联网 发布:三国志9优化伴侣设置 编辑:程序博客网 时间:2024/05/17 22:50

1.   什么是单例模式及其特点?

单例模式:即保证一个java类在java虚拟机中仅仅有一个实例对象。

单例模式主要有三个特点:

A)  单例类确保自己只有一个实例

B)  单例类必须自己创建自己的实例

C)  单例类必须为其他对象提供唯一实例


2.  单例模式的好处,为什么要用单例模式?

保证正常使用,在java虚拟机中只有一个对象,减少开销

3.话不多说,我们来看具体代码实现

a)    饿汉式

    //饿汉式public class Singleton {    //饿汉式,随着类的加载初始化对象    private static Singleton instance=new Singleton();    //将构造方法隐藏  private Singleton() {       // TODOAuto-generated constructor stub  }  //饿汉模式获取实例对象  public static Singleton getInstance(){      return instance;  }}

注解:由于instanceSingleton的静态变量,随着类的加载而加载并初始化,还没调用getInstance方法时就已经存在java虚拟机中,即称为饿汉式。因为随着类的加载而过早创建对象,占用虚拟机内存,如果实例化instance很好资源,则会大大降低了内存使用率。因此,需要改进方式,在调用getInstance方法获取对象实例时才对instance初始化,于是就有懒汉式。

b)    懒汉式(线程不安全)

public class Singleton {// 懒汉式,随着类的加载没有初始化对象private static Singleton instance = null;// 将构造方法隐藏private Singleton() {// TODO Auto-generated constructor stub}// 懒汉式调用方法时初始化对象public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}

注解:只有在调用getInstance方法时,才对instance初始化。如果instancenull,则new一个Singleton对象,如果不为null,即instance已初始化,返回instance。当线程A和线程B同时进入到if(instance==null)中时,即instance=new Singleton();会执行两次,创建不止一个对象。因此这种方式效率高,但线程不安全,只适合单线程使用。

c)    懒汉式(线程安全)

//懒汉式(线程安全)public class Singleton {// 懒汉式,随着类的加载没有初始化对象private static Singleton instance = null;// 将构造方法隐藏private Singleton() {// TODO Auto-generated constructor stub}// 懒汉式调用方法时初始化对象public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}

注解:为了防止b)中情况的发生,在getInstance方法上加同步锁,即同一时刻只能有一个线程进来,避免了创建出多个对象的可能。但每次调用时都要获取同步锁,加锁很耗时,只有当instancenull且需要初始化时,才需要加同步锁,所以没有必要每次获取对象都要获取同步锁,所以有了双重验证式。


d)    双重验证式

//双重验证public class Singleton {private static Singleton instance = null;private Singleton() {// TODO Auto-generated constructor stub}public static  Singleton getInstance() {if (instance == null) {synchronized(Singleton.class){if(instance==null){instance = new Singleton();}}}return instance;}}

注解:第一重验证,当instancenull时,才需要加同步锁来创建对象,当instance不为空时,则不需要加同步锁,提高了效率。但代码实现较为复杂。


e)    静态内部类式

//静态内部类public class Singleton {private Singleton() {// TODO Auto-generated constructor stub}//静态内部类private static class SingletonHolder{private static final Singleton INSTANCE = new Singleton();  } //获取静态内部类中Singleton 对象 INSTANCEpublic static Singleton getInstance(){return SingletonHolder.INSTANCE;}}

注解:这种方式利用了ClassLoader工作机制,保证了instance初始化时只有一个线程。它不同于饿汉式,饿汉式当Singleton类加载时,instance初始化;而现在Singleton类加载时,SingletonHolder并没有主动加载,即没有初始化instance,在调用getInstance方法时加载SingletonHolder而初始化instance

f)    枚举式

public enum SingletonEnum {INSTANCE; public   void show() {         System.out.println("我是枚举式"+INSTANCE);  }}

枚举式测试

SingletonEnum instance1=SingletonEnum.INSTANCE;instance1.show();SingletonEnum instance2=SingletonEnum.INSTANCE;instance2.show();//判断是否是同一对象if(instance1==instance2){System.out.println("同一个instance");}else {System.out.println("不是同一个instance");}

测试结果表明是同一个实例对象。


最后还有一种枚举式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象

综合以上,我们可以将b)和c)归为一类—懒汉式,即单例模式可以归纳为5中方式:饿汉,懒汉,双重验证,静态内部类,枚举。此处我们先无视java反射机制,暂时当它不存在。往后会继续更新java单例与反射的内容。

参考:http://www.cnblogs.com/hupp/p/4487521.html  

参考:http://www.blogjava.net/kenzhh/archive/2013/03/15/357824.html









































































原创粉丝点击