Java设计模式:单例设计模式

单例设计模式:解决一个类在内存中只存在一个对象,单例设计模式主要有两种实现方式:懒汉式,饿汉式。

1.为了保证只有一个对象,先禁止其他程序创建该类对象。

2.为了保证其他程序能访问该类对象,只好在本类中先创建好该类的一个对象。

3.对外提供一个其他程序访问该对象的方式。

 

什么是线程安全?

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

或者说:一个类或者程序所提供的接口对于线程来说是原子操作,或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题,那就是线程安全的。

一:懒汉式单例


public class Singleton {

//创建一个该类的实例
private static Singleton s = null;
//将构造方法私有化,避免了类被外界实例化
private Singleton(){}
//当该方法被使用的时候才去创建该类的实例
public static Singleton getInstance(){
   if(s==null){
    s = new Singleton();
   }
      return s;
}
}

 上述代码如果多线程访问会出现安全隐患,内存中可能出现多个Singleton类的实例化对象,若想保证线程安全,则需对getInstance方法进行改造。这种改造分为三种方式。

1.在getInstance方法上加上同步

	public static synchronized Singleton getInstance(){
		if(s==null){
			s = new Singleton();
		}
		return s;
	}	

  此种方式可以实现多个线程并发访问getInstance方法时,线程的安全性,当一个线程访问getInstance时,该线程对该方法加锁,别的线程暂时无法访问。缺点:任意一个线程若要拿到Singleton 对象的实例都要判断锁,线程比较多的时候会比较低效。

2.双重检查锁定

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

 

      在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗。

3.静态内部类

public class Instance {

	private static class LazyHolder{
		private static final Instance INSTANCE = new Instance();
	}
	private Inner(){};
	public static final Instance getInstance(){
return LazyHolder.INSTANCE;
}
}

  当getInstance方法第一次被调用的时候,它第一次读取LazyHolder.instance,内部类LazyHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Instance的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。

 

二.饿汉式单例

 

public class Single {

	private static final Single s = new Single();
	
	private Single(){}
	
	public static Single getInstance(){
		return s;
	}
}

  饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

 

 

posted @ 2017-10-09 12:03  清风晚霞  阅读(111)  评论(0)    收藏  举报