饿汉式

  1. public class Single1 {
  2. private static Single1 singleOne = new Single1();
  3. private Single1(){}
  4. public static Single1 getSingleOne() {
  5. return singleOne;
  6. }
  7. }
  • 加载类的时候就创建了对象(不论该对象有没有使用)

    懒汉式

    1. public class Single2 {
    2. private static Single2 single2;
    3. private Single2(){}
    4. public static Single2 getSingle2() {
    5. if (single2 == null) {
    6. single2 = new Single2();
    7. }
    8. return single2;
    9. }
    10. }
  • 解决了饿汉式的问题,但是在多线程环境下使用依然可能创建多个对象

    懒汉式加锁

    1. public class Single3 {
    2. private static volatile Single3 single3;
    3. private Single3(){}
    4. public static synchronized Single3 getSingle3() {
    5. if (single3 == null) {
    6. single3 = new Single3();
    7. }
    8. return single3;
    9. }
    10. }
  • 解决了懒汉式中线程不安全的问题,但是在方法中加锁退变成了单线程执行的模式

    双重检查锁形式

    1. public class Single4 {
    2. private static volatile Single4 single4;
    3. private Single4(){}
    4. public static Single4 getSingle4() {
    5. // 第一个判断是为了避免所有的线程都直接进入 同步代码块
    6. if (single4 == null) {
    7. synchronized (Single4.class) {
    8. // 如果没有该判断,可能多个线程都进入第一个if块,虽然同步块只有一个线程可以执行,但是已经进入第一个if块的代码还是可以执行new 命令,
    9. // 这样就不能实现单例
    10. if (single4 == null) {
    11. single4 = new Single4();
    12. }
    13. }
    14. }
    15. return single4;
    16. }
    17. }
  • 解决懒汉式的问题,这种方式已经算是比较完美的了,只是不能防止反序列化的形式来创建对象

    使用内部类的形式创建单例

    1. public class Single6 {
    2. private Single6() {
    3. }
    4. private static class InnerSingle6 {
    5. private static Single6 single6 = new Single6();
    6. }
    7. public static Single6 getSingle6() {
    8. return InnerSingle6.single6;
    9. }
    10. }

    使用枚举的形式来创建单例

    1. public class Single5 {
    2. private Single5(){}
    3. private enum Single5Enum {
    4. INSTANCE;
    5. private Single5 single5;
    6. Single5Enum() {
    7. this.single5 = new Single5();
    8. }
    9. }
    10. public static Single5 getSingle5() {
    11. return Single5Enum.INSTANCE.single5;
    12. }
    13. }
  • 枚举是不能使用 new 关键字来创建对象的,所以可以防止使用反序列化的形式来创建对象

  • 由于枚举中的对象在一开始就创建好了,所以在多线程环境下使用也是线程安全的