传统的两私有一公开(私有构造方法、私有静态实例(懒实例化/直接实例化)、公开的静态获取方法)涉及线程安全问题(即使有多重检查锁也可以通过反射破坏单例),
目前最为安全的实现单例的方法是通过内部静态enum的方法来实现,因为JVM会保证enum不能被反射并且构造器方法只执行一次。
实现方法如下:
/**
* 使用枚举的单例模式
*
* @author yzl
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class EnumSingleton{
private EnumSingleton(){}
public static EnumSingleton getInstance(){
return Singleton.INSTANCE.getInstance();
} private static enum Singleton{
INSTANCE; private EnumSingleton singleton;
//JVM会保证此方法绝对只调用一次
private Singleton(){
singleton = new EnumSingleton();
}
public EnumSingleton getInstance(){
return singleton;
}
}
}
测试方法:
public static void main(String[] args) {
EnumSingleton obj1 = EnumSingleton.getInstance();
EnumSingleton obj2 = EnumSingleton.getInstance();
//输出结果:obj1==obj2?true
System.out.println("obj1==obj2?" + (obj1==obj2));
}
扩展应用,观察下面的例子
public class Test{
//初始化一些东西
static{ }
}
这是一个很常见的类内部的静态资源初始化的写法(其实也就是单例的另外一种表现-只执行一次),但是将代码都写在static块下会看起来很不优雅,可以利用上面的enum单例模式来进行初始化操作。
见例子:
import java.util.ArrayList;
import java.util.List; /**
* 初始化的优雅实现
* 可以在static处调用,
* 也可以在普通方法里调用,都保证只初始化一次
*
* 当然将enum块的代码直接放到StaticInitTest类的private static 方法里做也是可以的
*
* @author yzl
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class StaticInitTest {
private static List<Integer> dataList = null; static{
dataList = Singleton.INSTANCE.init();
} /**
*
* 单例模式来填充数据
*
* @author yzl
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
private static enum Singleton {
INSTANCE;
private List<Integer> list; private Singleton(){
fillData();
}
/**
*
* 初始化数据
*
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
private void fillData(){
list = new ArrayList<Integer>(5);
for(int i =1; i<6; i++){
list.add(i);
}
} /**
*
* 初始化的入口
*
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public List<Integer> init(){
return list;
}
}
}