单例模式,顾名思义,就是确保一个类只有一个实例,并提供一个全局访问点。
public class BasicSingleton {
private static BasicSingleton instance;
private BasicSingleton(){}
public static BasicSingleton getInstance(){
if(null == instance)
instance = new BasicSingleton();
return instance;
}
}
上述代码算是最原始的单例模式实现,俗称懒汉模式,通过将构造方法私有化实现拒绝外部创建该类实例,同时开放一个静态方法返回一个全局唯一的实例对象。
仔细分析,上述代码中判断实例对象是否为空的条件之处在多线程环境下会存在线程安全的问题,对象可能会被重复创建,那如果事先就创建好相应单例对象实例,线程安全的问题就可以解决了,这便是饿汉模式单例。
public class HungrySingleton {
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton() {
if(null != instance){
throw new RuntimeException("单例模式被破坏");
}
System.out.println("HungrySingleton 私有构造方法");
}
public static HungrySingleton getInstance(){
return instance;
}
}
实例对象instance在类加载的时候便会被创建,因此在使用静态方法获取单例对象实例的时候不会有线程安全的问题。
当然,我们也可以对上述的懒汉模式稍作修改,使用线程同步的方法实现线程安全,这就是DCL双检查锁模式。
public class DCLSingleton implements Serializable{
private static volatile DCLSingleton _instance;
private DCLSingleton(){
synchronized (DCLSingleton.class){
if(null != _instance){
throw new RuntimeException("单例模式被侵犯!");
}
}
}
public static DCLSingleton getInstance(){
if(null == _instance){
synchronized (DCLSingleton.class){
if(null == _instance){
_instance = new DCLSingleton();
return _instance;
}
}
}
return _instance;
}
}
这里有两个地方需要注意,一个是实例对象instance使用volatile关键字修饰,保证任何修改能马上被线程感知,同时使用synchronized关键实现代码同步,保证线程安全。
Java规范中规定,每一个枚举类型极其定义的枚举变量在JVM中都是唯一的,由此可知,枚举天生保证序列化单例。
public class EnumSingleton {
private enum SingletonEnum{
singletonFactory;
private Singleton instance;
SingletonEnum(){
this.instance = new Singleton();
}
public Singleton getInstance() {
return instance;
}
}
public static Singleton getInstance(){
return SingletonEnum.singletonFactory.getInstance();
}
}
class Singleton{
public Singleton(){
System.out.println("Singleton的构造方法");
}
}
当然,最后我们还可以通过内部类的方法实现单例模式。
public class InnerClassSingleton implements Serializable{
private static class Singleton{
private static final InnerClassSingleton _instance = new InnerClassSingleton();
}
private InnerClassSingleton(){
if(null != Singleton._instance){
throw new RuntimeException("单例模式被侵犯");
}
}
public static InnerClassSingleton getInstance(){
return Singleton._instance;
}
}