题目:设计一个类,我们只能生成该类的一个实例。
只能生成一个实例的类是实现了Singleton(单例)模式的类型。由于设计模式在面向对象程序设计中起着举足轻重的作用,在面试过程中很多公司都喜欢问一些与设计模式相关的问题。在常用的模式中,Singleton是唯一一个能够用短短几十行代码完整实现的模式。因此,写一个Singleton的类型是一个很常见的面试题。
在Java中主要有6种方法能够实现单例模式。
1.饿汉模式
缺点:不管有没有调用过getSingleton(),每次都会新建一个实例。
public class Singleton{
//一开始就新建一个实例
private static final Singleton singleton = new Singleton();
//默认构造方法
private Singleton() {}
//获得实例的方法
public static Singleton getSingleton(){
return singleton;
}
}
2.懒汉模式
一开始没有新建实例,但是不能保证线程安全。
public class Singleton{
private static Singleton singleton; //一开始没有新建实例
private Singleton() {}
public static Singleton getSingleton(){ //需要时再新建
if(single == null){
singleton = new Singleton();
}
return singleton;
}
}
3.线程安全的懒汉模式
能够解决懒汉模式的线程安全问题,但是效率不高。仅在懒汉模式的基础上对getSingleton()函数加上synchronized关键字修饰即可。
public class Singleton{
private static Singleton singleton;
private Singleton() {}
public static synchronized Singleton getSingleton(){ //保证线程安全
if(single == null){
singleton = new Singleton();
}
return singleton;
}
}
方法1,2,3均存在缺陷,而后面的方法4,5,6为可行的方法。
4.双重检验锁(Double Check)
解决方法3效率不高的问题
public class Singleton{
private volatile static Singleton singleton;
//此处添加volatile关键字为了防止编译器自行优化代码(由于singleton = new Singleton()这句代码要做好几件事情)
private Singleton() {}
public static Singleton getSingleton(){
if(singleton == null){ //第一个检验锁
synchronized(Singleton.class){
if(singleton == null){ //第二个检验锁
singleton = new Singleton();
}
}
}
return singleton;
}
}
5.静态内部类
双重检验锁的代码看起来比较复杂,静态内部类方法相对简洁。
public class Singleton{
private static class SingletonHolder{
private static final Singleton singleton = new Singleton();
}
private Singleton() {}
public static Singleton getSingleton(){
return SingletonHolder.singleton;
}
}
6.枚举
枚举方法的代码最为简洁。
public enum Singleton{
INSTANCE;
public void whateverMethod() {}
}
//在外部通过Singleton.INSTANCE来访问实例对象