单例模式实现
- 一、单例模(60分)
- 二、饿汉式单例(70分)
- 三、懒汉式单例(80分)
- 四、双重检查锁定(90分)
- 五、静态内部类(100分)
- 六、枚举(100分)
一、单例模(60分)
单例模式保证一个类只有一个实例,并且提供一个访问它的全局访问点。
私有的构造方法,确保用户无法通过new关键字直接实例化它。
静态的公有工厂方法,该工厂方法检验实例的存在性和实例的创建。
静态方法使用成员变量,成员变量必须是静态的。
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
单例模式的问题:
遇到多线程时,就无法实现单例了。
二、饿汉式单例(70分)
当类被加载时,静态变量instance被初始化,调用getInstance返回唯一实例。
能确保实例为唯一性。
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {
}
public static EagerSingleton getInstance() {
return instance;
}
}
饿汉的问题:
类被加载时,实例就已经创建好了,即使不用也一直占用内存。
实际应用中,软件的加载速度会变慢。
三、懒汉式单例(80分)
在类的加载过程中不实例化,而是等到需要的时候再调用——延迟加载(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 保证枚举类型不能被反射并且构造函数只被执行一次
以上内容参考刘伟老师上课的讲解和博客内容