在代码的编写中,我们通常希望一个类只能有一份实例,这也就是我们通常所说的单例模式。在这里我将介绍几种高效的单例模式的java编写。
1、枚举类型的单例
枚举类型的单例主要是解决的反序列化的单列问题,我们知道反射总是会反回一个新的实例。枚举类型的单列也为我们决绝多线程中单列同步的问题。这种写法也是effective java中推荐的一种写法,但是还没有普遍使用,注意jdk1.5以上才可以这么写。
enum Singleton2{
INSTANCE;
//枚举中构造方法默认是私有的
private Singleton2(){}
public void sayHello(){
System.out.println("hello");
}
}
2、内部静态类实现方式
内部静态内的写法是一种延迟加载的策略,同过在类的内部声明一个静态属性类,并在内的内部通过懒汉模式创建一个单列。为什么这样做可以做到延迟加载和同步的作用可以去了解下类的初始化和类加载过程。
class Singleton3{
private static class Holder{
private final static Singleton3 INSTANCE = new Singleton3();
}
public static Singleton3 getInstance(){
return Holder.INSTANCE;
}
}
3、双重检测实现方式
注意在恶汉模式下创建单列是要考虑线程同步问题的,在调用getInstance()方法获取单列时,可能有多个线程同时在调用该方法,那么如果instance还未初始化的话即为null,多个线程得知这一条件会创建N的实例,所以会出错。volatile这个关键字修饰单列对象可以达到立即写入主存的效果,这样可以及时通知其它线程该值的引用已经改变。
public class SingleTon1 {
private volatile static SingleTon1 instance = null;
private SingleTon1(){}
public static SingleTon1 getInstance(){
//第一次检查,查看是否是第一次实例化
if(instance == null){
synchronized(SingleTon1.class){
//第二次检查,这时候可能有多个线程中调用了getInstance方法
//为了避免出现实例化两次,则需要锁住该类资源,并检查是否已经实例化过了
if(instance == null){
instance = new SingleTon1();
}
}
}
return instance;
}
}
4、简单恶汉模式实现方式
class Singleton4{
private static volatile Singleton4 INSTANCE = null;
private Singleton4(){};
public static synchronized Singleton4 getInstance(){
if(INSTANCE == null){
INSTANCE = new Singleton4();
}
return INSTANCE;
}
}
5、简单懒汉模式实现方式
class Singleton5{
private static final Singleton5 INSTANCE = new Singleton5();
private Singleton5(){};
public static Singleton5 getInstance(){
return INSTANCE;
}
}