做网站要找什么,关键词优化排名易下拉稳定,建筑做网站,wordpress自动生成文章目录
前言 1.饿汉式
2.懒汉式
3.双重检测 4.静态内部类
5.枚举
总结#xff1a; 前言
单例模式是我们日常开发过程中#xff0c;遇到的最多的一种设计模式。通过这篇文章主要分享是实现单例的几种实现方式。 1.饿汉式 饿汉式的实现方式比较简单。在类加载的时候#…目录
前言 1.饿汉式
2.懒汉式
3.双重检测 4.静态内部类
5.枚举
总结 前言
单例模式是我们日常开发过程中遇到的最多的一种设计模式。通过这篇文章主要分享是实现单例的几种实现方式。 1.饿汉式 饿汉式的实现方式比较简单。在类加载的时候instance 静态实例就已经创建并初始化好了所以instance 实例的创建过程是线程安全的。不过这样的实现方式不支持延迟加载从名字中我们也可以看出这一点。具体的代码实现如下所示 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();}
}
2.懒汉式
懒汉式相对于饿汉式的优势是支持延迟加载。具体的代码实现如下所示 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();}
}
懒汉式的缺点也很明显我们给 getInstance() 这个方法加了一把大锁synchronzed导致这个函数的并发度很低。量化一下的话并发度是 1也就相当于串行操作了。而这个函数是在单例使用期间一直会被调用。如果这个单例类偶尔会被用到那这种实现方式还可以接受。但是如果频繁地用到那频繁加锁、释放锁及并发度低等问题会导致性能瓶颈这种实现方式就不可取了。
3.双重检测 饿汉式不支持延迟加载懒汉式有性能问题不支持高并发。那我们再来看一种既支持延迟加载、又支持高并发的单例实现方式也就是双重检测实现方式。在这种实现方式中只要 instance 被创建之后即便再调用 getInstance() 函数也不会再进入到加锁逻辑中了。所以这种实现方式解决了懒汉式并发度低的问题。具体的代码实现如下所示 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();}
} 实际上上述实现方式存在问题CPU 指令重排序可能导致在 IdGenerator 类的对象被关键字 new 创建并赋值给 instance 之后还没来得及初始化执行构造函数中的代码逻辑就被另一个线程使用了。这样另一个线程就使用了一个没有完整初始化的 IdGenerator 类的对象。要解决这个问题我们只需要给 instance 成员变量添加 volatile 关键字来禁止指令重排序即可。 4.静态内部类 我们再来看一种比双重检测更加简单的实现方法那就是利用 Java 的静态内部类。它有点类似饿汉式但又能做到了延迟加载。具体是怎么做到的呢我们先来看它的代码实现 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 来保证。所以这种实现方法既保证了线程安全又能做到延迟加载。
5.枚举 我们介绍一种最简单的实现方式基于枚举类型的单例实现。这种实现方式通过 Java 枚举类型本身的特性保证了实例创建的线程安全性和实例的唯一性。具体的代码如下所示 public enum IdGenerator {INSTANCE;private AtomicLong id new AtomicLong(0);public long getId() { return id.incrementAndGet();}
}
总结
在日常的工作中使用枚举类的方式创建单例是最安全的。
枚举可避免被反序列化破坏单例。原因枚举对象的序列化、反序列化有自己的一套机制序列化时仅仅是将枚举对象的name属性输出到结果中反序列化的时候则是通过java.lang.Enum的valueOf()方法来根据名字查找枚举对象。
推荐大家使用枚举的方式创建单例。