Java 中的延迟加载模式:通过按需对象初始化提高性能
也称为
- 延迟初始化
延迟加载设计模式的意图
Java 中的延迟加载设计模式推迟对象初始化,直到对象真正需要时,从而最大限度地减少内存使用并缩短启动时间。这种技术对于优化 Java 应用程序性能至关重要。
延迟加载模式的详细解释以及现实世界的例子
现实世界的例子
Java 中延迟加载模式的现实世界类比是使用智能家居中的灯光。当有人进入房屋时,不是立即打开所有灯光,而是通过运动传感器检测并仅打开正在使用的房间的灯光。这反映了 Java 开发人员如何通过延迟对象创建来优化性能。
通俗地讲
延迟加载模式推迟对象的创建或资源的加载,直到它真正需要时,从而优化内存使用并提高性能。
维基百科说
延迟加载(也称为异步加载)是一种在计算机编程中使用的技术,特别是在网页设计和网页开发中,用于推迟对象的初始化,直到它需要时才进行。如果使用得当且合理,它可以提高程序运行效率。这使得它非常适合在访问网络内容和需要将初始化时间保持在最低限度的情况下使用,例如网页。例如,推迟网页上图像的加载,直到需要查看它们,可以加快网页的初始显示。延迟加载的相反是预加载。
Java 中延迟加载模式的编程示例
延迟加载设计模式是一种性能优化技术,它推迟对象的初始化或代价高昂的计算,直到绝对必要时才进行。这种模式可以通过避免不必要的计算和减少内存使用来显著提高应用程序的性能。
在提供的代码中,我们可以看到 App
、HolderNaive
、HolderThreadSafe
和 Java8Holder
类中延迟加载模式的一个示例。
App
类是应用程序的入口点。它创建 HolderNaive
、HolderThreadSafe
和 Java8Holder
的实例,并从它们中检索 Heavy
对象。
@Slf4j
public class App {
public static void main(String[] args) {
var holderNaive = new HolderNaive();
var heavy = holderNaive.getHeavy();
LOGGER.info("heavy={}", heavy);
var holderThreadSafe = new HolderThreadSafe();
var another = holderThreadSafe.getHeavy();
LOGGER.info("another={}", another);
var java8Holder = new Java8Holder();
var next = java8Holder.getHeavy();
LOGGER.info("next={}", next);
}
}
HolderNaive
、HolderThreadSafe
和 Java8Holder
类是延迟加载模式的实现,具有不断提高的复杂性。
HolderNaive
类是模式的一个简单、非线程安全的实现。
public class HolderNaive {
private Heavy heavy;
public HolderNaive() {
LOGGER.info("HolderNaive created");
}
public Heavy getHeavy() {
if (heavy == null) {
heavy = new Heavy();
}
return heavy;
}
}
HolderThreadSafe
类是模式的一个线程安全的实现,但每次访问时都需要进行大量同步。
public class HolderThreadSafe {
private Heavy heavy;
public synchronized Heavy getHeavy() {
if (heavy == null) {
heavy = new Heavy();
}
return heavy;
}
}
Java8Holder
类是模式的最高效实现,利用了 Java 8 功能。
public class Java8Holder {
private Supplier<Heavy> heavy = this::createAndCacheHeavy;
public Java8Holder() {
LOGGER.info("Java8Holder created");
}
public Heavy getHeavy() {
return heavy.get();
}
private synchronized Heavy createAndCacheHeavy() {
class HeavyFactory implements Supplier<Heavy> {
private final Heavy heavyInstance = new Heavy();
public Heavy get() {
return heavyInstance;
}
}
if (!(heavy instanceof HeavyFactory)) {
heavy = new HeavyFactory();
}
return heavy.get();
}
}
在这个示例中,App
类从 HolderNaive
、HolderThreadSafe
和 Java8Holder
中检索 Heavy
对象。这些类推迟了 Heavy
对象的创建,直到它真正需要时,展示了延迟加载模式。
何时在 Java 中使用延迟加载模式
在以下情况下使用延迟加载
- 对象的创建需要大量资源,并且可能并不总是被使用。
- 您需要推迟对象创建以优化内存使用或提高启动时间。
- 加载数据或资源应该在需要时才进行,而不是在应用程序启动时。
Java 中延迟加载模式的现实世界应用
- Hibernate(Java ORM 框架):推迟相关对象的加载,直到它们被访问,利用延迟加载模式来优化 Java 应用程序性能。
- JPA 注解 @OneToOne、@OneToMany、@ManyToOne、@ManyToMany 和 fetch = FetchType.LAZY
- Spring 框架(依赖注入):仅在需要时才加载 Bean,从而缩短应用程序启动时间。
延迟加载模式的优点和权衡
优点
- 通过仅在需要时初始化对象来减少内存使用。
- 通过推迟昂贵的对象创建来提高应用程序启动性能。
权衡
- 如果对象相互依赖,则实现会更加复杂。
- 如果初始化发生在意外的时间点,则存在延迟峰值的风险。