Намерих следния код тук: http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
Опитвам се да разбера защо има определени случаи, в които това не работи. Прочетох обяснението на "фините" проблеми и че използването на volatile
ще реши проблема, но съм малко объркан.
// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
// other functions and members...
}
По принцип прав ли съм да предположа, че това ще се провали поради факта, че проверката helper == null
в блока synchronized
има шанс да се провали, защото може да бъде "частично" конструирана в този момент? Java не връща ли нула, ако даден обект е частично конструиран? Това ли е проблемът?
Както и да е, знам, че не е добра практика да се прави заключване с двойна проверка, но просто бях любопитен на теория защо горният код се проваля и защо volatile (плюс добавянето на присвояване на локална променлива) коригира това? Ето някакъв код, който взех отнякъде.
// 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;
}
Знам, че вече има хиляди публикации за това, но обясненията изглежда споменават промени в модела на паметта след 1.5 и не разбирам какво общо има това също :-(.
Благодаря предварително!