单例模式实现

  • 一、单例模(60分)
  • 二、饿汉式单例(70分)
  • 三、懒汉式单例(80分)
  • 四、双重检查锁定(90分)
  • 五、静态内部类(100分)
  • 六、枚举(100分)


一、单例模(60分)

单例模式保证一个类只有一个实例,并且提供一个访问它的全局访问点。

java 允许的字符 java允许单独的方法存在_开发语言

  • 私有的构造方法,确保用户无法通过new关键字直接实例化它。
  • 静态的公有工厂方法,该工厂方法检验实例的存在性和实例的创建。
  • 静态方法使用成员变量,成员变量必须是静态的。
public class Singleton {
	private static Singleton instance = null;
	
	private Singleton() {
		
	}
	
	public static Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

单例模式的问题:

  • 遇到多线程时,就无法实现单例了。

二、饿汉式单例(70分)

java 允许的字符 java允许单独的方法存在_java_02

  • 当类被加载时,静态变量instance被初始化,调用getInstance返回唯一实例。
  • 能确保实例为唯一性。
public class EagerSingleton {
	private static final EagerSingleton instance = new EagerSingleton();
	
	private EagerSingleton() {
	
	}
	
	public static EagerSingleton getInstance() {
		return instance;
	}
}

饿汉的问题:

  • 类被加载时,实例就已经创建好了,即使不用也一直占用内存。
  • 实际应用中,软件的加载速度会变慢。

三、懒汉式单例(80分)

java 允许的字符 java允许单独的方法存在_java_03

  • 在类的加载过程中不实例化,而是等到需要的时候再调用——延迟加载(Lazy Load)
  • 避免多线程同时调用getInstance,使用关键字synchronized。
public class LazySingleton {
	private static LazySingleton instance = null;
	
	private LazySingleton() {
		
	}
	//synchronized,保证任意时刻只有一个线程执行下面方法
	synchronized public static LazySingleton getInstance() {
		if(instance == null) {
			instance = new LazySingleton();
		}
		return instance;
	}
}

懒汉的问题:

  • A,B同时调用getInstance,例如A进入去创建,B等待,当A创建完成之后,B不知道是实例是否被创建,进入方法继续创建实例。违背单例的设计思想。

四、双重检查锁定(90分)

public class LazySingleton {
	private volatile static LazySingleton instance = null;
	
	private LazySingleton() {
		
	}
	
	public static LazySingleton getInstance() {
		if(instance == null) {//一重判定
			synchronized(LazySingleton.class) {
				if(instance == null) {//二重判定
					instance = new LazySingleton();
				}
			}
		}			
		return instance;
	}
}

注意:

  • 使用双重检查,成员变量必须使用volatile去修饰,因为java虚拟机会判定其中一个判定为无用判定,直接略去一个判定。
  • c#可以使用这种方式

五、静态内部类(100分)

  • IoDH,创建静态内部类,在类部类中用final修饰变量,并且实例化对象
public class Singleton {
	
	private Singleton() {
		
	}
	
	private static class HolderClass{
		private final static Singleton instance = new Singleton();
	}
	
	public static Singleton getInstance() {
		return HolderClass.instance;
	}
	
}

说明:

  • IoDH实现延迟加载,类加载时不会实例化Singletotn。
  • IoDH保证线程安全,第一次调用getInstance时,加载内部类HolderClass,实例化其成员变量instance,JAVA虚拟机保证线程的安全性。
  • IoDH不影响系统性能,getInstance方法没有线程锁定,性能不会造成影响。

六、枚举(100分)

Java虚拟机会保证枚举对象的唯一性,每一个枚举类型和定义的枚举变量在JVM中都是唯一的。

public enum Singleton {
     INSTANCE;
     public void businessMethod() {
          System.out.println("我是一个单例!");
     }
}
public class Singleton {
	//私有的构造方法
    private Singleton(){
    }   
    //静态的枚举类型
    public static enum SingletonEnum {
    	//枚举类型的实例对象Singleton
        SINGLETON;
        private Singleton instance = null;
        //枚举类型的实例对象Singleton
        private SingletonEnum(){
            instance = new Singleton();
        }
        //返回
        public Singleton getInstance(){
            return instance;
        }
    }
}
JVM	保证枚举类型不能被反射并且构造函数只被执行一次

以上内容参考刘伟老师上课的讲解和博客内容