Lazy initialization - It decreases the cost of initializing a class or creating an instance, at the expense of increasing the cost of accessing the lazily initialized field. Depending on what fraction of lazily initialized fields eventually require initialization, how expensive it is to initialize them, and how often each field is accessed, lazy initialization can (like many "optimizations") actually harm performance.

The only way to know for sure is to measure the performance of the class with and without lazy initialization.

Principle

  • Normal initialization of an instance field - Under most circumstances, normal initialization is preferable to lazy initialization.

    // Normal initialization of an instance field

    private final FieldType field = computeFieldValue();

  • synchronized accessor - If you use lazy initialization to break an initialization circularity, use a synchronized accessor, as it is the simplest, clearest alternative:

    // Lazy initialization of instance field - synchronized accessor

    private FieldType field;

    synchronized FieldType getField() {

    if (field == null)

    field = computeFieldValue();

    return field;

    }

    Both of these idioms (normal initialization and lazy initialization with a synchronized accessor ) are unchanged when applied to static fields, except that you add the static modifier to the field and accessor declarations.

  • lazy initialization holder class idiom - If you need to use lazy initialization for performance on a static field, use the lazy initialization holder class idiom .

    // Lazy initialization holder class idiom for static fields

    private static class FieldHolder {

    static final FieldType field = computeFieldValue();

    }

    static FieldType getField() { return FieldHolder.field; }

  • Double-check idiom - If you need to use lazy initialization for performance on an instance field, use the double-check idiom.

    // Double-check idiom for lazy initialization of instance fields

    private volatile FieldType field;

    FieldType getField() {

    FieldType result = field;

    if (result == null) { // First check (no locking)

    synchronized(this) {

    result = field;

    if (result == null) // Second check (with locking)

    field = result = computeFieldValue();

    }

    }

    return result;

    }

  • Single-check idiom - Occasionally, you may need to lazily initialize an instance field that can tolerate repeated initialization.

    // Single-check idiom - can cause repeated initialization!

    private volatile FieldType field;

    private FieldType getField() {

    FieldType result = field;

    if (result == null)

    field = result = computeFieldValue();

    return result;

    }

    Note

    When the double- check or single-check idiom is applied to a numerical primitive field, the field's value is checked against 0 (the default value for numerical primitive variables) rather than null.

  • Racy single-check idiom - If you don't care whether every thread recalculates the value of a field, and the type of the field is a primitive other than long or double , then you may choose to remove the volatile modifier from the field declaration in the single-check idiom(e.g. String instances to cache their hash codes).

    // racy single-check idiom - can cause repeated initialization!

    private FieldType field;

    private FieldType getField() {

    FieldType result = field;

    if (result == null)

    field = result = computeFieldValue();

    return result;

    }

    Summary

    You should initialize most fields normally, not lazily. If you must initialize a field lazily in order to achieve your performance goals, or to break a harmful initialization circularity, then use the appropriate lazy initialization technique. For instance fields, it is the double-check idiom; for static fields, the lazy initialization holder class idiom. For instance fields that can tolerate repeated initialization, you may also consider the single-check idiom.

Effective Java 71 Use lazy initialization judiciously的更多相关文章

  1. Effective Java 54 Use native methods judiciously

    Java Native Interface(JNI) allows Java applications to call native methods, which are special method ...

  2. Effective Java Index

    Hi guys, I am happy to tell you that I am moving to the open source world. And Java is the 1st langu ...

  3. 《Effective Java》读书笔记 - 10.并发

    Chapter 10 Concurrency Item 66: Synchronize access to shared mutable data synchronized这个关键字不仅保证了同步,还 ...

  4. Effective Java 目录

    <Effective Java>目录摘抄. 我知道这看起来很糟糕.当下,自己缺少实际操作,只能暂时摘抄下目录.随着,实践的增多,慢慢填充更多的示例. Chapter 2 Creating ...

  5. 【Effective Java】阅读

    Java写了很多年,很惭愧,直到最近才读了这本经典之作<Effective Java>,按自己的理解总结下,有些可能还不够深刻 一.Creating and Destroying Obje ...

  6. Effective Java通俗理解(下)

    Effective Java通俗理解(上) 第31条:用实例域代替序数 枚举类型有一个ordinal方法,它范围该常量的序数从0开始,不建议使用这个方法,因为这不能很好地对枚举进行维护,正确应该是利用 ...

  7. Effective java笔记(九),并发

    66.同步访问共享的可变数据 JVM对不大于32位的基本类型的操作都是原子操作,所以读取一个非long或double类型的变量,可以保证返回的值是某个线程保存在该变量中的,但它并不能保证一个线程写入的 ...

  8. 单例模式的两种实现方式对比:DCL (double check idiom)双重检查 和 lazy initialization holder class(静态内部类)

    首先这两种方式都是延迟初始化机制,就是当要用到的时候再去初始化. 但是Effective Java书中说过:除非绝对必要,否则就不要这么做. 1. DCL (double checked lockin ...

  9. Effective Java 阅读笔记——并发

    66:同步访问共享的可变数据 synchronized:1互斥,阻止线程看到的对象处于不一致的状态:2保证线程在进入同步区时能看到变量的被各个线程的所有修改 Java中,除了long或者double, ...

随机推荐

  1. 最近一段时间开发客户端app的感悟

    关于android和cocos2d 凭着对大学时候写html+css的一点点的记忆,我还是认为android的布局xml文件还是参考了html+css,只是他更加臃肿!就想 android平台本身那样 ...

  2. 对象Transform,对属性赋值

    private void ContructRequest(Dictionary<string, string> dictionary, CustomerSearchRequest requ ...

  3. 通过Nginx实现负载均衡

    百度了下负载均衡:英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web服务器.FTP服务器.企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务 嗯,跟我理 ...

  4. thread_AtomicBoolean

    Boolean值的变化的时候不允许在之间插入,保持操作的原子性 它提供了原子性操作,其中exists.compareAndSet(false, true)这个操作把比较和赋值操作组成了一个原子操作,中 ...

  5. 很有趣的Java分形绘制

    部分与整体以某种形式相似的形,称为分形. 首先我们举个例子:        我们可以看到西兰花一小簇是整个花簇的一个分支,而在不同尺度下它们具有自相似的外形.换句话说,较小的分支通过放大适当的比例后可 ...

  6. 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符

    [源码下载] 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 结构体 ...

  7. kFreeBsd 国内开源镜像站汇总

    从http://bbs.chinaunix.net/archiver/tid-3756178.html这里抽取了debian源中支撑kfreebsd架构的源. 中科大: http://debian.u ...

  8. 【NOIP训练】【Tarjan求割边】上学

    题目描述 给你一张图,询问当删去某一条边时,起点到终点最短路是否改变. 输入格式 第一行输入两个正整数,分别表示点数和边数.第二行输入两个正整数,起点标号为,终点标号为.接下来行,每行三个整数,表示有 ...

  9. ACdrea 1217---Cracking' RSA(高斯消元)

    ACdrea  1217---高斯消元 Description The following problem is somehow related to the final stage of many ...

  10. Spark集群 + Akka + Kafka + Scala 开发(4) : 开发一个Kafka + Spark的应用

    前言 在Spark集群 + Akka + Kafka + Scala 开发(1) : 配置开发环境中,我们已经部署好了一个Spark的开发环境. 在Spark集群 + Akka + Kafka + S ...