徐无忌并发编程笔记:案例实战:线程安全的单例模式几种实现方式?

完成:第一遍

1.线程安全的单例模式有几种实现方式?

方式一:懒汉式加载
懒汉式单例
1.线程安全
2.采用同步方法

当使用时才创建instance
优点:起到lazy loading的效果,线程安全,synchronized同步方法同一时间只会有一个线程进入
缺点:加锁,效率低,并发情况下,每个线程在获取实例时都需要进行同步

package code01;

public class LazySingleton {

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

方式二:双重检查的懒汉式加载
懒汉式单例
1.线程安全
2.采用双重检查

1.volatile保证可见性和有序性
2.当instance被一个线程实例化后,实时地刷新到主内存中的共享变量存储中
3.当一个线程修改了volatile修饰的instance变量,其他线程会立即看到最新的值

将锁进行细化,保证线程安全的前提下,可以多个线程进行实例化获取

我们以为的new操作应该是:
1.分配一块内存 M
2.在内存M 上初始化 DoubleCheck 对象
3.然后M的地址赋值给instance对象

其实new操作通过指令重排后发生:
1.分配一块内存 M
2.然后M的地址赋值给instance对象
3.最后在内存M 上初始化 DoubleCheck 对象

package code01;

public class DoubleCheck {

	 private static volatile DoubleCheck instance;

	  private DoubleCheck(){
	  }

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

方式三:静态内部类的懒汉式加载
懒汉式单例
1.线程安全
2.静态内部类实现

外部类StaticInnerSingleton加载时,不会加载静态内部类Inner
只有静态内部类的静态属性被调用时,才会加载,可实现延时加载功能

优点:1.加载机制避免了线程安全问题
JVM必须确保一个类在初始化的过程中,如果是多线程需要同时初始化它,仅仅只能允许其中一个线程对其执行初始化操作,其余线程必须等待。
静态只加载一次
2.方法没有同步,调用效率高
3.保证了懒加载

class StaticInnerSingleton{

	private StaticInnerSingleton() {
			}
			
	private static class Inner{
		private static final StaticInnerSingleton instance = 
		                                     new StaticInnerSingleton();
	}

	public static StaticInnerSingleton getInstance() {
		return Inner.instance;
	}
}

方式四:静态变量或静态代码块的饿汉式加载
优点:采用静态变量或静态代码块,类加载时就完成了instance的实例化,类只加载一次避免线程同步
缺点:如果从始至终都没有使用过这个instance,造成内存的浪费

package code01;

public class Singleton {

	//静态变量
	private final static Singleton instance1 = new Singleton();
	
	//静态代码块
	private final static Singleton instance2;
	
	static{
		
		instance2 = new Singleton();
	}
	
	private Singleton(){
		
	}
	
	public static Singleton getInstance1(){
		return instance1;
	}
	public static Singleton getInstance2(){
		return instance2;
	}
}

方式五:枚举式饿汉式加载
通过类加载机制保证线程安全的
直接通过EasySingleton.INSTANCE进行访问

public enum EasySingleton{
    INSTANCE;
}