Java单例模式详解

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 对象 INSTANCE
		public 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









































































你可能感兴趣的:(Java设计模式)