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. NPTL 线程同步方式

    NPTL提供了互斥体 pthread_mutex_t 类型进行线程同步,防止由于多线程并发对全局变量造成的不正确操作.使用 pthread_mutext_t 对数据进行保护已经可以实现基本的数据同步, ...

  2. SQL语句技巧之去除重复行

    去除表中重复行数据,可能大家立马就想到的是用DISINTCT关键字,但DISINTCT只能是去除表中所有列都相同的行,若碰到需要去除表中多个字段重复的行(即:部份相同,部份不相同),那么该如何做呢?我 ...

  3. 基于GTID Replication主从数据不一致操作

    基本的M-S结构   现在master与slave主机数据一致:   mysql> select * from t1; +------+ | id   | +------+ |    1 | | ...

  4. Spring基础—— Bean 的作用域

    一.在 Spring Config 文件中,在 <bean> 元素的 scope 属性里设置 Bean 的作用域.默认为 singleton ,单例的. 二.在不引入 spring-web ...

  5. Swift使用FMDB操作SQLite

    SQLite大家都懂的.本地数据库,在移动设备上使用广泛.IOS平台上自然也少不了它.最近自己折腾一个小App的时候需要使用sqlite本地数据库,上Github搜了下IOS下对SQLite的三方封装 ...

  6. ASP.NET MVC5--为数据库新增字段(涉及数据库迁移技术)

    Setting up Code First Migrations for Model Changes--为模型更改做数据库迁移. 1.打开资源管理器,在App_Data文件夹下,找到movies.md ...

  7. [水煮 ASP.NET Web API2 方法论](3-5)路由约束

    问题 怎么样限制路由中参数的值. 解决方案 ASP.NET WEB API 允许我们通过 IHttpRouteConstraint 接口设置路由约束.集中式路由和直接式路由都可以使用 IHttpRou ...

  8. Java的final关键字详解

    Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使 ...

  9. 【循序渐进学Python】9.异常处理

    1. 抛出异常和自定义异常 Python用异常对象(exception object)表示异常情况,遇到错误后,会引发异常.如果异常对象并未被处理或捕捉,程序就会用所谓的回溯(Traceback,一种 ...

  10. EF工作中踩过的坑.

    1.EF同一个linq里边不支持两个或两个以上不同dbcontext的使用,必须拆解开才能使用; ef也不支持自定义集合和dbcontext属性的混合使用. 2.如果要用用统一域账号连接databas ...