定义


单例模式

确保一个类在整个系统中只有一个实例,并提供一个全局访问点来访问该实例。

实现方式


懒汉式(线程不安全)


public class Singleton {  
	
    private static Singleton instance;  
    
    private Singleton (){
    }  
 
    public static Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

优点:实现了懒加载,只在需要时才实例化instance,节省了资源。
缺点:线程不安全,在多线程环境下,如果有多个线程同时进入if (instance == null),同时instancenull,就可能有多个线程执行instance = new Singleton();,从而导致多次实例化。

懒汉式(线程安全)


public class Singleton {  
	
    private static Singleton instance;  
    
    private Singleton (){
    }  
	
    public static synchronized Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

优点:通过给getInstance加锁实现了线程安全。
缺点:在instance实例化后锁依然存在,只有拿到锁的线程才能进入该方法,性能上有损耗。

饿汉式(线程安全)


public class Singleton {  
	
    private static Singleton instance = new Singleton();
    
    private Singleton (){
    }  
	
    public static Singleton getInstance() {  
        return instance;  
    }  
}

优点:提前实例化instance,避免了线程不安全的问题。
缺点:没有实现懒加载,如果该实例并没有被使用就会造成资源浪费。

双重检查锁(线程安全)


public class Singleton { 
	// volatile 禁止指令重排,防止instance指向未初始化完成的实例
	private volatile static Singleton instance;
	
	private Singleton() {
	} 
	
	public static Singleton getInstance() {  
		if (instance == null) {  
			synchronized (Singleton.class) {  
				// 第二个if:防止多个线程进入第一个if从而导致instance被多次实例化
				if (instance == null) {  
					instance = new Singleton(); 
				}
			}
		}
		return instance; 
	} 
}

优点:实现懒加载的同时也实现了线程安全。
volatile关键字的作用:
instance = new Singleton(); 这行代码在 JVM 层面分为三步执行:

  1. 分配内存空间。
  2. 初始化对象(执行构造函数)。
  3. instance 指向分配的内存地址。
    但是因为 JVM 的指令重排,执行顺序可能变成了1 -> 3 -> 2。如果执行了3却还没有执行2,此时正好有其他线程访问该方法,就会拿到一个未初始化完成的实例。

静态内部类(线程安全)


public class Singleton {
 
    private Singleton() {
    }
	
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
 
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

优点:实现懒加载的同时也实现了线程安全。
懒加载:当外部类 Singleton 被加载时,内部类 SingletonHolder 并不会被立即加载。当第一次调用getInstance() 方法时,JVM 才会去加载 SingletonHolder 并初始化INSTANCE
线程安全:JVM保证了只会实例化一次。

枚举


public enum Singleton {
 
	INSTANCE; 
	
	// 业务方法
	public void doSomething() {
	} 
}

优点:实现简单,线程安全,防止反射攻击。
缺点:没有实现懒加载。