延迟初始化(lazy initialization),也就是在真正被使用的时候才开始初始化的技巧。
不论是静态还是实例,都可以进行延迟初始化。
其本质是初始化开销和访问开销之间的权衡。
毕竟是一种优化技巧,使用不当会起反效果。
尤其是在多线程场景中这种反效果会尤为明显,因为我们要对这个进行延迟初始化的field进行同步。

先一步步开始,如果初始化开销不值一提,我们只需要保证其不可变即可:

private final FieldType field1 = computeFieldValue();

如果还有的商量,初始化开销可能让人在意,下面是最简单的的方式,直接在访问方法声明里加了synchoronized修饰,这种方式将访问开销最大化了:

private FieldType field2;

synchronized FieldType getField2() {
if (field2 == null)
field2 = computeFieldValue();
return field2;
} private static FieldType computeFieldValue() {
return new FieldType();
}

如果要改为静态的也不过是加上static修饰,但对于静态初始化,我们可以使用class holder方式:

private static class FieldHolder {
static final FieldType field = computeFieldValue();
} static FieldType getField3() {
return FieldHolder.field;
} private static FieldType computeFieldValue() {
return new FieldType();
}

这种方式感觉不错,我们没有进行额外的同步处理,只有在访问getField3的时候FieldHolder才会被初始化。
所以这种情况属于没有增加访问开销也保证了延迟特性。

这次试试优化一下实例field的访问开销,最经典的就是double-check了,这个东西经常出现在笔试题中:

private volatile FieldType field4;

FieldType getField4() {
FieldType result = field4;
if (result == null) {
synchronized (this) {
result = field4;
if (result == null)
field4 = result = computeFieldValue();
}
}
return result;
}
private static FieldType computeFieldValue() {
return new FieldType();
}

代码中使用了result局部变量,这样做虽然不是必要的,但这样可以确保field已被初始化的情况下被读取一次,可以提高少许效率。

以上就是延迟初始化的一些常用方式。
延迟初始化看起来不错,但建议权衡访问和创建的开销,对于实例field使用double-check,对于静态field使用holder class,以在多线程访问时保证check-then-action的原子性。

Java - 延迟初始化的更多相关文章

  1. Effective Java 第三版——83. 明智谨慎地使用延迟初始化

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  2. JAVA 双重检查锁定和延迟初始化

    双重检查锁定的由来在Java程序中,有时需要推迟一些高开销的对象的初始化操作,并且只有在真正使用到这个对象的时候,才进行初始化,此时,就需要延迟初始化技术.延迟初始化的正确实现是需要一些技巧的,否则容 ...

  3. Java对象延迟初始化的实现

    一.什么是延迟初始化? 在Java多线程程序中,有时候需要采用延迟初始化来降低初始化类和创建对象的开销. 延迟初始化实际上就是:当我们要进行一些高开销的对象初始化操作时,只有在使用这些对象时才进行初始 ...

  4. Effective Java 之-----关于延迟初始化

    1.大多数情况下,正常的初始化要优先于延迟初始化. private final FieldType field = computeFieldValue(); 2.如果利用延迟优化来破坏初始化的循环,就 ...

  5. 从学习“单例模式”学到的Java知识:双重检查锁和延迟初始化

    一切真是有缘,上午刚刚看完单例模式,还在为其中的代码块同步而兴奋,下午就遇见这篇文章:双重检查锁定与延迟初始化.我一看,文章开头语出惊人,说这是一种错误的优化,我说,难道上午学的东西下午就过时了吗?仔 ...

  6. 双重检查锁定与延迟初始化(转自infoq)

    很好的文章,转自http://www.infoq.com/cn/articles/double-checked-locking-with-delay-initialization 在java程序中,有 ...

  7. volatile双重检查锁定与延迟初始化

    一.基本概念: 1.volatile是轻量级的synchronized,在多核处理器开发中保证了共享变量的“可见性”.可见性的意思是,当一个线程修改一个共享变量时,另一个线程能读到这个修改的值. 2. ...

  8. spring3: 延迟初始化Bean

    3.3.1  延迟初始化Bean 延迟初始化也叫做惰性初始化,指不提前初始化Bean,而是只有在真正使用时才创建及初始化Bean. 配置方式很简单只需在<bean>标签上指定 “lazy- ...

  9. (转)Android高性能编程(2)--延迟初始化

    上一篇文章,讲到了很多Android应用开发中需要注意的性能和内存方面的技巧.这一篇文章就是从smali指令级来分析性能优化和内存优化的问题. 如何解决界面启动时间开销大的问题 我们在编写Androi ...

随机推荐

  1. Android TV Overscan

    本文来自网易云社区 作者:孙有军 开发的TV应用发现在部分电视上可以显示完整,而其他部分电视显示不全,周围都会遮挡了. 原因 这是因为部分老的电视有一个overscan的概览,什么叫overscan呐 ...

  2. jqury的ajax

    前端代码: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEnc ...

  3. iOS推送功能极光推送的介绍与实现

    1.个人整理操作流程 2.官方使用说明流程 2018iOS极光推送完整流程 极光推送官网

  4. BZOJ 1003--[ZJOI2006]物流运输(最短路)

    1003: [ZJOI2006]物流运输 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10034  Solved: 4403 Description ...

  5. tzhpxc

    #include<bits/stdc++.h> using namespace std; int nxt[200100],las[200100],ct,va[200010],pos[410 ...

  6. 从 falcon api 中获取数据

    import json import time import requests openfalcon = 'http://ip:port/api/v1' user = 'user' password ...

  7. java的几种定时任务

    本篇博文主要是讲述2.x 版本的quartz下的实现方案,1.x 版本的实现方式大致原理一致,但是具体的实现方式有些不一致,具体体现在获取  scheduler 这个类的方式上有些不同,这里不作过多的 ...

  8. JMeter性能测试-服务器资源监控插件详解

          零.引言 我们对被测应用进行性能测试时,除了关注吞吐量.响应时间等应用自身的表现外,对应用运行所涉及的服务器资源的使用情况,也是非常重要的方面,通过实时监控,可以准确的把握不同测试场景下服 ...

  9. oracle case when 语句的用法详解

    1. CASE WHEN 表达式有两种形式 复制代码代码如下: --简单Case函数  CASE sex  WHEN '1' THEN '男'  WHEN '2' THEN '女'  ELSE '其他 ...

  10. iOS多线程---GCD中线程的通信

    在子线程的任务完成后,有时候需要从子线程回到主线程,刷新UI. 从子线程中回到主线程,以前已经写过一种方法: [self.imageView performSelectorOnMainThread:@ ...