饿汉模式

  1. public class EagerSingleton {
  2. private static final EagerSingleton instance = new EagerSingleton();
  3. private EagerSingleton() {
  4. }
  5. public static EagerSingleton getInstance() {
  6. return instance;
  7. }
  8. }

懒汉模式

  1. public class LazySingleton {
  2. private static volatile LazySingleton instance = null;
  3. private LazySingleton() {
  4. }
  5. public static LazySingleton getPerson() {
  6. if (instance == null) {
  7. synchronized (LazySingleton.class) {
  8. if (instance == null) {
  9. instance = new LazySingleton();
  10. }
  11. }
  12. }
  13. return instance;
  14. }
  15. }

如果不加volatile指令重排的情况下,单例会变成多例。
http://ifeve.com/jmm-faq-dcl/

看似简单的一段赋值语句:instance = new LazySingleton();,其实JVM内部已经转换为多条指令: memory = allocate(); //1:分配对象的内存空间 ctorInstance(memory); //2:初始化对象 instance = memory; //3:设置instance指向刚分配的内存地址 但是经过重排序后如下: memory = allocate(); //1:分配对象的内存空间 instance = memory; //3:设置instance指向刚分配的内存地址,此时对象还没被初始化 ctorInstance(memory); //2:初始化对象 可以看到指令重排之后,instance指向分配好的内存放在了前面,而这段内存的初始化被排在了后面,在线程A初始化完成这段内存之前,线程B虽然进不去同步代码块,但是在同步代码块之前的判断就会发现instance不为空,此时线程B获得instance对象进行使用就可能发生错误。

内部类模式

  1. public class IoDHSingleton {
  2. private IoDHSingleton() {
  3. }
  4. public static IoDHSingleton getInstance() {
  5. return HolderClass.instance;
  6. }
  7. private static class HolderClass {
  8. private final static IoDHSingleton instance = new IoDHSingleton();
  9. }
  10. }

如何破坏单例

  • 反射
  • 序列化

JDK中的单例

  1. public class Runtime {
  2. private static Runtime currentRuntime = new Runtime();
  3. /**
  4. * Returns the runtime object associated with the current Java application.
  5. * Most of the methods of class <code>Runtime</code> are instance
  6. * methods and must be invoked with respect to the current runtime object.
  7. *
  8. * @return the <code>Runtime</code> object associated with the current
  9. * Java application.
  10. */
  11. public static Runtime getRuntime() {
  12. return currentRuntime;
  13. }
  14. /** Don't let anyone else instantiate this class */
  15. private Runtime() {}
  16. }