RFR: 8023168 - Cleanup LogManager class initialization and LogManager/LoggerContext relationship
Daniel Fuchs
daniel.fuchs at oracle.com
Thu Sep 5 12:43:55 UTC 2013
On 9/5/13 1:51 PM, Peter Levart wrote:
>> Threads that call ensureLogManagerInitialized() after that will find
>> the flag
>> is true before entering the synchronized block and will return directly.
>
> ...and such threads can see rootLogger field being either still null or
> not null but the Logger instance that is obtained via such data race can
> be half-initialized.
I don't think so, because the flag isn't set to true until
the initialization is finished.
BTW - there was a reason for having both an initializationCalled
*and* a synchronized at method level. The purpose of
initializationCalled flag was to prevent infinite recursion in the
same thread - because addLogger within ensureLogManagerInitialized
will trigger a new call to ensureLogManagerInitialized that the
synchronized won't block - since it's in the same thread.
So I need in fact two flags: one initializationDone - which will
be volatile - the other initializationCalled - which doesn't need
to be since it will be always written/read from within the
synchronized block.
I toyed with the idea of using a single volatile three valued byte
instead:
initialization: 0 => uninitialized, 1 => initializing, 2 => initialized
I opted for the two booleans - but the three valued byte might be more
efficient:
1)
volatile byte initialization = 0;
ensureLogManagerInitialized() {
if (initialization == 2) return; // already done
synchronized(this) {
if (initialization > 0) return;
initialization = 1; // avoids recursion
try {
// do stuff which might recurse on
// ensureLogManagerInitialized()
} finally {
initialization = 2; // mark as done
}
}
}
vs 2)
volatile boolean initializationDone = false;
boolean initializationCalled = false;
ensureLogManagerInitialized() {
if (initializationDone) return; // already done
synchronized(this) {
if (initializedCalled || initializationDone) return;
initializedCalled = true; // avoids recursion
try {
// do stuff which might recurse on
// ensureLogManagerInitialized()
} finally {
initializationDone = true; // mark as done.
}
}
}
Don't know if you have a preference for one or the other.
My current impl (still under test) is 2)
best regards,
-- daniel
>
>> I can make rootLogger volatile. I'm not 100% sure it is required - but
>> I think
>> it is more correct, and as such it will make the code more maintainable.
>> Good point. It's probably something I would have overlooked.
>
>
> I think volatile rootLogger field is required for correct publication of
> RootLogger instances if double-checked locking is used...
>
>
> Regards, Peter
>
More information about the core-libs-dev
mailing list