单例模式解析

模块:
    singleton
设计模式:
    单例
目的:
    保证JVM中只有一个实例存在。
解决问题:
    1.避免大型对象频繁创建;
    2.核心交易只能有单个服务存在。
说明:

1.双重校验锁DoubleCheckSingleton

public class DoubleCheckSingleton implements Serializable {
	private static final long serialVersionUID = 1L;
	private static DoubleCheckSingleton instance;

	private DoubleCheckSingleton() {
	}

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

	public Object readResolve() {
		return instance;
	}
}
    编译器优化,可能导致问题:先给对象申请内存,再赋值给instance,但还未执行初始化操作,导致另外一个线程取到一个未初始化的对象。

    该问题在不同的编译器下表现可能会不一样。
    不推荐

2.枚举EnumSingleton

public enum EnumSingleton implements Serializable{
	INSTANCE;
	
	private EnumSingleton(){
		System.out.println("init");
	}
	
	public void doBusiness() {
		System.out.println("working");
	}
	
	public static void main(String[] args) {
		EnumSingleton.INSTANCE.doBusiness();
	}
}

    这种方式是Effective Java作者Josh Bloch提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象.
    JDK1.5以上版本支持.
    推荐

3.饥饿模式HungryManSingleton

public class HungryManSingleton {
	private static HungryManSingleton instance = new HungryManSingleton();

	private HungryManSingleton() {
	}

	public static HungryManSingleton getInstance() {
		return instance;
	}
}

    这种方式基于classloder机制避免了多线程的同步问题,在类加载时就实例化对象。
    既然是大型对象才需要实例化,所以并不希望在类被加载时就实例化,希望在真正使用时再实例化,该模式无法实现懒加载。
    不推荐

4.懒汉模式LazyManSingleton

public class LazyManSingleton {
	private static LazyManSingleton instance = null;

	private LazyManSingleton() {
	}

	public static LazyManSingleton getInstance() {
		if (instance == null) {
			instance = new LazyManSingleton();
		}
		return instance;
	}
}
    getInstance()方法没有进行线程同步,线程不安全。

5.懒汉模式线程安全LazyManThreadSafeSingleton

public class LazyManThreadSafeSingleton {
	private static LazyManThreadSafeSingleton instance;

	private LazyManThreadSafeSingleton() {
	}

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

    getInstance()方法增加synchronized关键字,每次都是同步调用,性能较差。
    不推荐

6.静态内部类StaticInnerClassSingleton

public class StaticInnerClassSingleton {
	private static class SingletonHolder {
		private static StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
	}

	private StaticInnerClassSingleton() {
	}

	public static StaticInnerClassSingleton getInstance() {
		return SingletonHolder.INSTANCE;
	}
}

    classloader加载class文件时,JVM会保证只有一个线程,不会产生多线程处理的问题。且加载单例对象时,内部类不会被加载,实现了懒加载。
    推荐

7.双重校验锁synchronized解决编译优化问题SynchronizedDoubleCheckSingleton

public class SynchronizedDoubleCheckSingleton implements Serializable {
	private static final long serialVersionUID = 1L;
	private static SynchronizedDoubleCheckSingleton instance;

	private SynchronizedDoubleCheckSingleton() {
	}

	private static synchronized void syncInit() {
		if (instance == null) {
			instance = new SynchronizedDoubleCheckSingleton();
		}
	}

	public static SynchronizedDoubleCheckSingleton getInstance() {
		if (instance == null) {
			syncInit();
		}
		return instance;
	}

	public Object readResolve() {
		return instance;
	}
}

    将内部的校验锁独立到syncInit()方法里,对syncInit()进行同步。syncInit()方法结束时会保证intance对象被正确赋值。解决了编译器优化的问题。
    推荐

8.双重校验锁volatile解决编译优化问题VolatileDoubleCheckSingleton

public class VolatileDoubleCheckSingleton implements Serializable {
	private static final long serialVersionUID = 1L;
	private static volatile VolatileDoubleCheckSingleton instance;

	private VolatileDoubleCheckSingleton() {
	}

	public static VolatileDoubleCheckSingleton getInstance() {
		if (instance == null) {
			synchronized (VolatileDoubleCheckSingleton.class) {
				if (instance == null) {
					instance = new VolatileDoubleCheckSingleton();
				}
			}
		}
		return instance;
	}
}
    私有静态变量intance增加volatile关键字,保证每次修改了变量需要立即写回主内存中,同时通知所有的该对变量的缓存失效,保证缓存一致性,其他线程需要使用该共享变量时就要重新从住内存中获取最新的内容拷贝到工作内存中供处理器使用。保证变量修改在其他线程中的可见性。

    推荐


完整代码放在oschina

https://git.oschina.net/haxzheng/design-pattern.git


测试结果:
org.xzheng.designpattern.singleton.TestDoubleCheckSingleton
f 0 ms
*org.xzheng.designpattern.singleton.TestEnumSingleton
f 26 ms
org.xzheng.designpattern.singleton.TestHungryManSingleton
f 36 ms
org.xzheng.designpattern.singleton.TestLazyManSingleton
f 48 ms
org.xzheng.designpattern.singleton.TestLazyManThreadSafeSingleton
f 62 ms
*org.xzheng.designpattern.singleton.TestStaticInnerClassSingleton
f 76 ms
*org.xzheng.designpattern.singleton.TestSynchronizedDoubleCheckSingleton
f 99 ms
*org.xzheng.designpattern.singleton.TestVolatileDoubleCheckSingleton
f 109 ms
参考性能测试结果,推荐的4中写法中,枚举EnumSingleton性能最佳。

PS:
单例对象序列化测试
    PASSED: testEnumSingleton
    PASSED: testSingletonWithoutReadResolve
    FAILED: testSingletonWithReadResolve
    java.lang.AssertionError: expected [1591044672] but found [322977463]
如果单例对象被用于序列化,增加readResolve()可以保证对象在序列化前后保持一致.
    public Object readResolve() {
        return instance;
    }
另外,枚举类型单例EnumSingleton天生支持防止反序列化重新创建新的对象。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值