Skip to content

Double-check idiom for lazy initialization of instance fields. Broken example. #8

@panph

Description

@panph

CHAPTER 11 CONCURRENCY
Item 83: Use lazy initialization judiciously

// Double-check idiom for lazy initialization of instance fields
private FieldType getField() {
	FieldType result = field; // (1)
	if (result == null) { // First check (no locking)
		synchronized (this) {
			if (field == null) // Second check (with locking)
				field = result = computeFieldValue(); // (2)
		}
	}
	return result;
}

This code is broken, because when one thread enters the line (2), other threads may have already read the field into result (line (1)), and it is null, so, when they enter the line (2), they see that field isn't null anymore, because it was already initialized by the first thread so, the method called by those non-first threads, when they start almost immediately after the first thread, returns null in spite that the field was initialized.

To fix this we need to reassign result to the field value again.

Here is a solution that works:

private FieldType getField() {
	FieldType result = field;
	if (result == null) { // First check (no locking)
		synchronized (this) {
			if (field == null) // Second check (with locking)
				field = result = computeFieldValue();
			else
				result = field;
		}
	}
	return result;
}

Or this one, which I like even more, because we check if result is not null first, which happens more often, or to be more precise, always after first initialization.

private FieldType getField() {
	FieldType result = field;
	if (result != null)
		return result;
	synchronized (this) {
		result = field;
		return result != null ? result : (field = computeFieldValue());
	}
}

Attached code demonstrates the error and how the fixes work.

I'm writing this not to accuse (everybody can mistake) Joshua Bloch, whom I respect much and find his book very useful, but to suggest to programmers to use copy-paste technique judiciously.

Thank you.

Lazy.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions