单例模式(Head First版)

单例模式:确保一个类只有一个实例,并提供一个全局访问点。

代码实现:

package com.headfirst.chapter5;

public class Singleton {
	private static Singleton singleton;
	private Singleton(){}
	public static Singleton getInstance(){
		if(singleton == null){
			singleton = new Singleton();
		}
		return singleton;
	}
}

上面这个例子在高并发情况下,很可能会产生两个实例。

即可能会有一个线程进入singleton = new Singleton()并且还未实例化,

另一个线程在singleton == null 为true。这样就会产生两个实例

将上面的getInstance方法加一个同步块。如下

package com.headfirst.chapter5;

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

 这样就能保证只生成一个实例,但在高并发情况下,这个方法会有性能问题。

继续修改,给singleton变量加上volatile修饰

并且只有在第一次实例化时,才会进同步块,这样就解决了同步的性能问题。

package com.headfirst.chapter5;

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

为什么不把singleton定义成全局的静态变量,如下

public static Singleton singleton = new Singleton();

如果这样写,那么在Singleton初始化的时候,这个变量就会被实例化,即急切实例化。

而不像上面的例子,只有在真正使用到这个变量的时候,才去实例化它。

Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。

而volatile使用时有明确的规定:

  1.       对变量的写操作不依赖于当前值;
  2.       该变量没有包含在具有其他变量的不变式中;

猜你喜欢

转载自mynote.iteye.com/blog/1539130