单例设计模式( Singleton Design Pattern):一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。

饿汉式

  1. public class HungrySingleton {
  2. private AtomicLong generator = new AtomicLong(0);
  3. //初始化加载,禁止重新赋值
  4. private static final HungrySingleton instance = new HungrySingleton();
  5. //禁止创建新对象
  6. private HungrySingleton() {
  7. }
  8. //唯一实例获取
  9. public static HungrySingleton getInstance() {
  10. return instance;
  11. }
  12. //功能
  13. public long getNextId() {
  14. return generator.getAndIncrement();
  15. }
  16. }

懒汉式

并发度太低

  1. public class LazySingleton {
  2. private AtomicLong generator = new AtomicLong(0);
  3. private static LazySingleton instance = null;
  4. //禁止外部创建
  5. private LazySingleton() {
  6. }
  7. //加锁,只创建一次
  8. //类锁,保证同一个类只有一个对象
  9. public static synchronized LazySingleton getInstance() {
  10. if (instance == null) {
  11. instance = new LazySingleton();
  12. }
  13. return instance;
  14. }
  15. public long getNextId() {
  16. return generator.getAndIncrement();
  17. }
  18. }

双重检测

解决懒汉式并发度低的问题

  1. public class DCSingleton {
  2. private AtomicLong generator = new AtomicLong(0);
  3. //
  4. private static DCSingleton instance = null;
  5. private DCSingleton() {
  6. }
  7. //只有没有实例化时候加锁,增加了并发度
  8. //类锁
  9. public static DCSingleton getInstance() {
  10. if (instance == null) {
  11. synchronized (DCSingleton.class) {
  12. if (instance == null) {
  13. instance = new DCSingleton();
  14. }
  15. }
  16. }
  17. return instance;
  18. }
  19. public long getNextId() {
  20. return generator.getAndIncrement();
  21. }
  22. }

有人说,这种写法会由于指令重排,在实例化后赋值给instance后还没有来得及初始化(调用构造函数中的初始化逻辑)就被其他线程调用,所以需要加上volatile字段。 实际上在高版本(1.5以后)java中已经解决了这个问题(让new操作和初始化操作设计为原子操作),因此不需要加volatile字段

静态内部类

  1. public class StaticInnerSingleton {
  2. private StaticInnerSingleton instance = null;
  3. private AtomicLong generator = new AtomicLong(0);
  4. public static class SingletonHolder {
  5. public static final StaticInnerSingleton instance = new StaticInnerSingleton();
  6. }
  7. public static StaticInnerSingleton getInstance() {
  8. return SingletonHolder.instance;
  9. }
  10. public long getNextId() {
  11. return generator.getAndIncrement();
  12. }
  13. }

外部类加载时候,内部类不会实例化;只有当调用 getinstance0方法时, Singletonholderオ会被加载,这个时候才会创建 instance。 insance的唯性、创建过程的线程安全性,都由JVM来保证。所以,这种实现方法既保证了线程安全,又能做到延退加载。

  1. public enum EnumSingleton {
  2. INSTANCE;
  3. private AtomicLong generator = new AtomicLong(0);
  4. public long getNextId() {
  5. return generator.getAndIncrement();
  6. }
  7. }