总结了一些单例模式的写法,当然,各种写法有利有弊,推荐方式三、四、五
单例模式
保证类的对象在内存中只有一个
- 方式一:
饿汉法
但是这样容易占用较多资源
/**
* 第一次引用该类的时候就创建对象实例
* 不管实际使用时是否需要创建
* 但是这样容易占用较多资源
*/
public class Singleton {
private Singleton(){
}
private static final Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
- 方式二:
只适用于单线程环境
/**
* 单线程写法
* 如果有两个线程同时调用getInstance方法,可能导致重复创建对象
*/
public class Singleton {
private Singleton(){
}
private static Singleton instance = null;
public static Singleton getInstance(){
if (instance == null)
instance = new Singleton();
return instance;
}
}
- 方式三:
DCL(Double Check Locking)双重检测方法
(在jdk1.5后才能保证安全使用)
/**
* DCL单例模式
*/
public class Singleton {
//用volatile关键字来禁止指令重排序和保证instance在多线程中的可见性
private volatile static Singleton instance;
public static Singleton getInstance(){
//因为并不是经常需要new一个对象,所以先判断一下是否需要,再进入synchronized同步块
//如果不在此处判断一下的话,很多次调用getInstance的线程(不需要new时)都会在synchronized这里排队,效率低下
if (instance == null){
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
- 方式四:枚举方法
这个还不太懂
/**
* 使用枚举除了线程安全和防止反射强行调用构造器之外,
* 还提供了自动序列化机制,防止反序列化的时候创建新的对象。
* 因此,Effective Java推荐尽可能地使用枚举来实现单例。
*/
public enum Singleton {
INSTANCE;
private String name;
public String getName(){
return name;
}
public void setName(){
this.name = name;
}
}
- 方式五:静态内部类法
/**
* 避免了静态实例在Singleton类加载的时候就创建对象,
* 并且由于静态内部类只会被加载一次,
* 所以这种写法也是线程安全的
*/
public class Singleton {
private static class Holder{
private static Singleton instance = new Singleton();
}
private Singleton(){
}
public static Singleton getInstance(){
return Holder.instance;
}
}