书写代码必须符合高质量高性能要求,这也是能够在视觉上和其他程序员拉开差距的技能,同时也是一个优秀程序员的基本要求。
何为高质量: 代码具备可维护性,可读性,可扩展性,灵活性,简洁性,可复用性, 可测试性。
何为高性能: 代码能尽可能的提高处理效率。
如何写高质量高性能代码: 首先要做的就是精通设计模式,设计原则,掌握各种算法以及了解硬件底层相关内容。
今天我们来说一说单例模式。
1单例模式
饿汉式
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();
}
}
懒汉式
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 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();
}
}
网上有人说,这种实现方式有些问题。因为指令重排序,可能会导致IdGenerator对象被new出来,并且赋值给instance之后,还没来得及初始化(执行构造函数中的代码逻辑),就被另一个线程使用了。 要解决这个问题,我们需要给instance成员变量加上volatile关键字,禁止指令重排序才行。实际上,只有很低版本的Java才会有这个问题。我们现在用的高版本的Java已经在JDK内部实现中解决了这个问题(解决的方法很简单,只要把对象new操作和初始化操作设计为原子操作,就自然能禁止重排序)。
静态内部类
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();
}
}
枚举
public enum IdGenerator {
INSTANCE;
private AtomicLong id = new AtomicLong(0);
public long getId() {
return id.incrementAndGet();
}
}
关于单利模式的实现,大体就是上面这几种,具体来说一下:
共同特征:
- 构造函数必须使用private修饰,避免外部创建;
- 都需要考虑安全问题;
- 是否支持延迟加载;
- 考虑性能问题;
不同点:
- 饿汉式实现简单,在类加载的时候静态实例就已经创建好了,因此,创建是安全的,但是不支持延迟加载,就有可能导致资源占用问题。
- 懒汉式略微复杂,支持延迟加载,但是实现中加了一把大锁,因此并发性低,性能低下。不适合频繁调用的场景。
- 双重检测的单例支持延迟加载,支持高并发,安全可靠,低版本的jdk可能创建单例对象时,可能会存在重排序的导出错,因此,最好是做下修改
private static IdGenerator instance
修改为
private static volatile IdGenerator instance
- 静态内部类的实现,因为jvm类加载本身就是默认延迟加载,此内部类只有在使用的时候才会被加载,因此支持延迟加载,因为是静态类,对象的创建是在类加载的时候,因此可以保证安全可靠,应该是一个具备延迟加载的饿汉式单例。
- 枚举的方式实现单例,这种实现方式通过java枚举型本身的特性,保证了实例创建的线程安全性和唯一性
如果需要带注释的spring源码或者了解更多行业技能请关注微信公众号 码农本农