背景
以前写过单例模式的文章(http://blog.csdn.net/cyxlzzs/article/details/7078548),这里根据最新的理解重新写一下单例模式的设计,主要写两种我认为最好的实现方式
单例模式之内部类实现
这里直接先上代码,后面总结
class RepositoryClass{
private static class RepositoryClassHolder{
private static RepositoryClass instance = new RepositoryClass();
}
private RepositoryClass(){
System.out.println("RepositoryClass constructor");
}
public static RepositoryClass getInstance(){
return RepositoryClassHolder.instance;
}
}
这里定义了一个数据仓库类
单例模式之枚举实现
也是先上代码
enum RepositoryEnum{
INSTANCE; //单例对象
private RepositoryEnum(){
System.out.println("RepositoryEnum constructor");
}
public static RepositoryEnum getInstance(){
return INSTANCE;
}
}
该枚举的作用和上面的仓库类是一样的
测试代码
public static void main(String[] args){
List<RepositoryClass> intances1 = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
RepositoryClass instance = RepositoryClass.getInstance();
intances1.add(instance);
}, "t"+String.valueOf(i)).start();
}
List<RepositoryEnum> intances2 = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
RepositoryEnum instance = RepositoryEnum.getInstance();
intances2.add(instance);
}, "t"+String.valueOf(i)).start();
}
while(Thread.activeCount()>1){
Thread.yield();
}
System.out.println("==============");
intances1.forEach(System.out::println);
System.out.println("==============");
intances2.forEach(System.out::println);
}
输出结果
RepositoryClass constructor
RepositoryEnum constructor
==============
RepositoryClass@5fd0d5ae
RepositoryClass@5fd0d5ae
RepositoryClass@5fd0d5ae
RepositoryClass@5fd0d5ae
RepositoryClass@5fd0d5ae
RepositoryClass@5fd0d5ae
RepositoryClass@5fd0d5ae
RepositoryClass@5fd0d5ae
RepositoryClass@5fd0d5ae
RepositoryClass@5fd0d5ae
==============
instance
instance
instance
instance
instance
instance
instance
instance
instance
instance
两种方式都适用了10个线程来进行获取对象实例并将实例放到list中,从结果可以看到,两种方式的构造方法都只执行了一次,而且对象实例list中的对象是相同的
总结对比
1、内部类实现的单例模式优点在于:懒加载,效率高,线程安全;缺点在于有些机制还是会破坏单例,比如序列化,反射和clone,当然可以有相应的机制来防止这些,可以在网上查一下解决的方法
2、枚举实现是jdk版本1.5以上才有的,但这种方式是实现单例模式的最好方式,推荐使用