单利模式是确保系统中某一个类只要一个实例。单例的类图如下:
代码清单:单例通用模板,饿汉式,线程安全。
public class Singleton {
/**
* static 初始化一个实例
*/
private static final Singleton singleton = new Singleton();
/**
* 构造函数私有化,防止new
*/
private Singleton(){}
/**
* 通过该方法向外提供实例
*/
public static Singleton getInstance(){
return singleton;
}
/**
* 其他方法,尽量使用static
*/
public static void other(){
}
}
代码清单:双重检查判断单例,懒汉式,线程安全。
public class Singleton {
/**
* volatile修饰
*/
private static volatile Singleton singleton;
/**
* 构造函数私有化,防止new
*/
private Singleton(){}
/**
* 通过该方法向外提供实例
*/
public static Singleton getInstance(){
if(singleton == null){
synchronized(Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
/**
* 其他方法,尽量使用static
*/
public static void other(){
}
}
代码清单:静态内部类,线程安全。
public class Singleton {
/**
* 静态内部类
*/
private static class SingletonInstance{
private static final Singleton INSTANCE = new Singleton();
}
/**
* 构造函数私有化,防止new
*/
private Singleton(){}
/**
* 通过该方法向外提供实例
*/
public static Singleton getInstance(){
return SingletonInstance.INSTANCE ;
}
/**
* 其他方法,尽量使用static
*/
public static void other(){
}
}
代码清单:序列化与反序列化,静态内部类,线程安全。
public class Singleton implements Serializable{
private static final long serialVersionUID = 4615796391914001196L;
/**
* 静态内部类
*/
private static class SingletonInstance{
private static final Singleton singleton = new Singleton();
}
/**
* 构造函数私有化,防止new
*/
private Singleton(){}
/**
* 序列化将这个类读入到内存(写入磁盘)中,而反序列化可以从内存(写入磁盘)中将其读出进而组装一个和
* 以前一摸一样的对象,不过当序列化遇到单例的时候,就出现了问题,这样破坏了单例的规则。JVM从内存中
* 反序列化一个新对象时,就会自动调用这个readResolve()来返回指定好的对象了,单例规则也就得到了保证。
*/
protected Object readResolve() throws ObjectStreamException{
return SingletonInstance.singleton ;
}
/**
* 通过该方法向外提供实例
*/
public static Singleton getInstance(){
return SingletonInstance.singleton ;
}
/**
* 其他方法,尽量使用static
*/
public static void other(){
System.out.println(getInstance().hashCode());
}
}
代码清单:静态代码块,饿汉式,线程安全。
public class Singleton {
private static Singleton singleton = null;
/**
* 构造函数私有化,防止new
*/
private Singleton(){}
/**
* 构造函数私有化,防止new
*/
static {
singleton = new Singleton();
}
/**
* 通过该方法向外提供实例
*/
public static Singleton getInstance(){
return singleton;
}
/**
* 其他方法,尽量使用static
*/
public static void other(){
}
}
代码清单:枚举数据类型实现单例模式,饿汉式,线程安全。
public class SingletonEnum {
public enum Singleton {
factory;
private String str;
/**
* 构造方法会被自动调用
*/
private Singleton() {
Random ran = new Random(1000);
this.str = ran.toString();
}
public String str() {
return str;
}
}
/**
* 获取实例
*/
public String getInstance() {
return Singleton.factory.str();
}
}
单例模式的缺点:
- 单例模式一般没有接口,扩展困难,若要修改,除了修改代码基本上没有其他方法可以实现;
- 单例模式不利于测试;
- 单利模式与单一职责有冲突;
注意:方法里面的变量是线程安全的。