You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
Hi Alexey. Ouch! I fixed this bug in the second printing of the book (February 2018). I had correct code in the first two editions of the book, and messed it up in the first printing of the the third edition. I publicly apologized and widely distributed the corrected code. You can also see the corrected code on the errata page. When I put the code examples on the web, though, I ran out of time and never got around to updating the code from the later chapters of the book. Thank you so much for bringing this to my attention.
I will fix this bug (in /src/effectivejava/chapter11/item83/Initialization.java) by tomorrow, but I will leave this issue open until I've updated all of the chapters that need it (at a minimum, the Github code for chapters 9-12 requires a once-over).
I apologize that I allowed this known bad code to exist in Github for over a year. I'm well aware of the responsibility that accompanies writing code that will be widely copy-pasted. I aim to illustrate best practices so that you can copy-paste my code without fear. In this case, I failed.
OK, I finally fixed the broken code. Sorry for the delay. I sincerely hope to find the time to go over the Github code for chapters 9-12 in the very near future (as promised), at which time I'll close this issue.
CHAPTER 11 CONCURRENCY
Item 83: Use lazy initialization judiciously
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:
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.
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
The text was updated successfully, but these errors were encountered: