单例模式饿汉式与懒汉式详解

单例模式饿汉式与懒汉式详解

步骤:
  • 私有构造方法,使得在类的外部不能调用此方法,限制产生多个对象
  • 类初始化时,区分饿汉式与懒汉式的区别
  • 对外部提供调用方法,将创建的对象返回,只能通过类来调用

饿汉式:

  1. 类加载时即创建对象,线程安全
  2. 优点:执行效率高
  3. 缺点:类加载时就初始化,浪费内存资源,懒加载:无
实现:
public class SingletonEH {

    /**
     * 饿汉式:
     *  类加载时即创建对象,线程安全
     *  优点:执行效率高
     *  缺点:类加载时就初始化,浪费内存资源,懒加载:无
     */
    private SingletonEH(){};

    private final static SingletonEH singletonEH = new SingletonEH();

    public static SingletonEH getInstance() {
        return singletonEH;
    } 
}
测试:
public static void main(String[] args) {
	SingletonEH instanceA = SingletonEH.getInstance();
	SingletonEH instanceB = SingletonEH.getInstance();
	System.out.println(instanceA == instanceB);
}
饿汉式测试结果:
true
Process finished with exit code 0

懒汉式:

  1. 只有再调用获取实例的时候,才会去初始化实例对象
  2. 懒加载:是
  3. 是否线程安全:否
private SingletonLH(){};
private static SingletonLH singletonLH; // 注意实现方式不同,实例私有化有变化
方式一:最基本的实现方式

不支持多线程,因为没有加锁

实现:
public static SingletonLH getSingletonLH() {
    if (null == singletonLH) {
        singletonLH =  new SingletonLH();
    }

    return singletonLH;
}
方式二:静态内部类

也即饿汉式和懒汉式的组合,调用 getInstance() 方法时才创建,达到了类似懒汉式的效果,同时又是线程安全的

实现:
private static class Holder{
    private static SingletonLH singletonStatic = new SingletonLH();
}

public static SingletonLH getInstanceLHStatic() {
    return Holder.singletonStatic;
}
方式三:加锁

synchronized

实现:
public static synchronized SingletonLH getInstanceSy() {
	
	if (null == singletonLH) {
		singletonLH =  new SingletonLH();
	}

	return singletonLH;
}
方式四:双重锁校验

通常线程安全,加volatile的作用是禁止指令重排。(由于 JVM 底层内部模型原因,偶尔会出问题。不建议使用)

private volatile static SingletonLH singletonLHVolatile;

public static SingletonLH getSingletonLHVolatile() {
	
	if (null == singletonLHVolatile) {
		synchronized (SingletonLH.class) {
			if (null == singletonLHVolatile) {
				singletonLHVolatile = new SingletonLH();
			}
		}
	}
	
	return singletonLHVolatile;
}
方式五:ThreadLocal方式

线程安全,ThreadLocal采用以空间换时间的方式,为每一个线程都提供一份变量,因此可以同时访问而互不影响。

实现:
private static final ThreadLocal<SingletonLH> singletonThreadLocal = new ThreadLocal<SingletonLH>(){
    @Override
    protected SingletonLH initialValue() {
    	return new SingletonLH();
    }
};

public static SingletonLH getInstanceThreadLocal() {
	return singletonThreadLocal.get();
}
方式六:CAS 锁方式

CAS锁(Compare and Swap):比较并交换,是一种有名的无锁算法,属于乐观锁)。用CAS锁来实现单例模式是线程安全的

实现:
private static final AtomicReference<SingletonLH> instanceCAS = new AtomicReference<SingletonLH>();

public static final SingletonLH getInstanceCAS() {
	for (; ; ) {
		
		SingletonLH instance = instanceCAS.get();
		if (null != instance) {
			return instance;
		}
		
		instance = new SingletonLH();
		if (instanceCAS.compareAndSet(null, instance)) {
			return instance;
		}
	}
}

​ 懒汉式还有一种实现方式就可以使用枚举,枚举实现的单例,代码简洁清晰。并且它还自动支持序列化机制,绝对防止多次实例化。这个大家自己可以动手实现下,代码就不粘贴出来了。

测试:
public static void main(String[] args) {
	SingletonLH instanceLHA = SingletonLH.getSingletonLH();
	SingletonLH instanceLHB = SingletonLH.getSingletonLH();
	System.out.println("基本懒汉式:" + (instanceLHA == instanceLHB));

	SingletonLH instanceLHStaticA = SingletonLH.getInstanceLHStatic();
	SingletonLH instanceLHStaticB = SingletonLH.getInstanceLHStatic();
	System.out.println("静态代码块式:" + (instanceLHStaticA == instanceLHStaticB));

	SingletonLH instanceSyA = SingletonLH.getInstanceSy();
	SingletonLH instanceSyB = SingletonLH.getInstanceSy();
	System.out.println("加锁式:" + (instanceSyA == instanceSyB));

	SingletonLH instanceLHVolatileA = SingletonLH.getSingletonLHVolatile();
	SingletonLH instanceLHVolatileB = SingletonLH.getSingletonLHVolatile();
	System.out.println("双重锁:" + (instanceLHVolatileA == instanceLHVolatileB));

	SingletonLH instanceThreadLocalA = SingletonLH.getInstanceThreadLocal();
	SingletonLH instanceThreadLocalB = SingletonLH.getInstanceThreadLocal();
	System.out.println("ThreadLocal方式:" + (instanceThreadLocalA == instanceThreadLocalB));

	SingletonLH instanceCASA = SingletonLH.getInstanceCAS();
	SingletonLH instanceCASB = SingletonLH.getInstanceCAS();
	System.out.println("CAS方式:" + (instanceCASA == instanceCASB));
}
懒汉式不同方式下的测试结果
基本懒汉式:true
静态代码块式:true
加锁式:true
双重锁:true
ThreadLocal方式:true
CAS方式:true

Process finished with exit code 0

你可能感兴趣的:(设计模式,java,单例模式,java,jvm)