23种设计模式-01单例模式

58 阅读1分钟

作用

只能创建1个实体对象

场景

构建配置类、连接池类、ID生成器类

用法

懒汉式
public class IdGenerator { 
  private AtomicLong id = new AtomicLong(0);
  private static IdGenerator instance;
  private IdGenerator() {}
  
  public static synchronized IdGenerator getInstance() {
    if (instance == null) {
      instance = new IdGenerator();
    }
    return instance;
  }
  public long getId() { 
    return id.incrementAndGet();
  }
}

缺点:每次获取对象,都要先获取锁资源

饿汉式
public class IdGenerator { 
    private AtomicLong id = new AtomicLong(0); 
    private static final IdGenerator instance = new IdGenerator(); 
    private IdGenerator() {} 
    public static IdGenerator getInstance() { 
      return instance; 
    } 
    public long getId() {
      return id.incrementAndGet(); 
    }
}

由虚拟机控制对象只初始化1次; 缺点:无法延迟加载,,系统启动时耗时慢一丢丢。

双重检测
public class IdGenerator { 
  private AtomicLong id = new AtomicLong(0);
  private static IdGenerator instance;
  private IdGenerator() {}
  public static IdGenerator getInstance() {
    if (instance == null) {
      synchronized(IdGenerator.class) { // 此处为类级别的锁
        if (instance == null) {
          instance = new IdGenerator();
        }
      }
    }
    return instance;
  }
  public long getId() { 
    return id.incrementAndGet();
  }
}

问题:如果是复杂的对象,是否会 初始化一半,被其他类调用?

静态内部类
public class IdGenerator { 
  private AtomicLong id = new AtomicLong(0);
  private IdGenerator() {}

  private static class SingletonHolder{
    private static final IdGenerator instance = new IdGenerator();
  }
  
  public static IdGenerator getInstance() {
    return SingletonHolder.instance;
  }
 
  public long getId() { 
    return id.incrementAndGet();
  }
}

SingletonHolder 是一个静态内部类,当外部类 IdGenerator 被加载的时候,并不会创建 SingletonHolder 实例对象。只有当调用 getInstance() 方法时,SingletonHolder 才会被加载,这个时候才会创建 instance。instance 的唯一性、创建过程的线程安全性,都由 JVM 来保证。所以,这种实现方法既保证了线程安全,又能做到延迟加载。

枚举
public enum IdGenerator {
  INSTANCE;
  private AtomicLong id = new AtomicLong(0);
 
  public long getId() { 
    return id.incrementAndGet();
  }
}

推荐该方式