单例模式写法有很多种,没有十全十美的。只要根据自己的情况定义合适的单例模式即可。下面我把所有单例模式写法汇总一遍:
1、最简单的单例,在确定程序没有多线程的情况下可以考虑这样写。既性能高又简单。
package com.zc;
/**
*
* @ClassName: Singleton1
* @Description: TODO(最简单的单例模式)
* @author zc
* @date 2015-3-25 下午04:42:29
*/
public class Singleton1 {
private static Singleton1 singleton1=null;
public static Singleton1 getInstance(){
if(singleton1 == null){
singleton1=new Singleton1();
}
return singleton1;
}
}
2、考虑到多线程问题,我们在方法上增加一个synchronized。但是这个会带来性能问题,因为每次调用getInstance方法,我们都要给对象加锁。
package com.zc;
/**
*
* @ClassName: Singleton1
* @Description: TODO(考虑到多线程问题)
* @author zc
* @date 2015-3-25 下午04:42:29
*/
public class Singleton2 {
private static Singleton2 singleton1=null;
public static synchronized Singleton2 getInstance(){
if(singleton1 == null){
singleton1=new Singleton2();
}
return singleton1;
}
}
3、考虑到多线程和性能问题,优化成如下:
package com.zc;
/**
*
* @ClassName: Singleton1
* @Description: TODO(考虑到多线程问题)
* @author zc
* @date 2015-3-25 下午04:42:29
*/
public class Singleton2 {
private static Singleton2 singleton1 = null;
public static Singleton2 getInstance() {
if (singleton1 == null) {
synchronized (Singleton2.class) {
if (singleton1 == null) {
singleton1 = new Singleton2();
}
}
}
return singleton1;
}
}
4、虽然多线程、性能都解决了,但是还有个问题,就是在java虚拟机中,创建一个对象,是要经过两个步骤,分配空间并赋值给对象实例,然后再去初始化这个实例。所以,就会有一种情况出现,当两个线程同事发现这个对象没有创建。其中一个只分配了空间并赋值给对象实例,但是没有初始化该实例,然后就跳出了同步代码块。接着另一个线程也进去了判断实例对象还是null。所以他又去创建了。
package com.zc;
/**
*
* @ClassName: Singleton1
* @Description: TODO(考虑到多线程问题)
* @author zc
* @date 2015-3-25 下午04:42:29
*/
public class Singleton3 {
private static class singleFactory{
private static Singleton3 singleton3=new Singleton3();
}
public static Singleton3 getInstance(){
return singleFactory.singleton3;
}
}
上面,我把单例模式总结了一下。总之,根据自己的情况选择合适的写法就可以了。