RFR: 8023168 - Cleanup LogManager class initialization and LogManager/LoggerContext relationship
Peter Levart
peter.levart at gmail.com
Thu Sep 5 11:51:11 UTC 2013
On 09/05/2013 10:08 AM, Daniel Fuchs wrote:
>> Or, without using yet another class, double-checked locking, like:
>>
>> private volatile boolean initializedCalled;
>>
>> final void ensureLogManagerInitialized() {
>> if (initializedCalled) {
>> return;
>> }
>> synchronized (this) {
>> final LogManager owner = this;
>> // re-check under lock
>> if (initializedCalled || owner != manager) {
>> // we don't want to do this twice, and we don't want to do
>> // this on private manager instances.
>> return;
>> }
>> try {
>> AccessController.doPrivileged(....);
>> } finally {
>> initializedCalled = true;
>> }
>> }
>> }
> Ah! Thanks for that comment Peter - that's exactly what I had in mind.
>>
>>
>> ... the code in PrivilegedAction that does the initialization, that
>> is, the following statements:
>>
>> owner.readPrimordialConfiguration();
>> * owner.rootLogger = owner.new RootLogger();*
>> owner.addLogger(owner.rootLogger);
>> final Logger global = Logger.global;
>> owner.addLogger(global);
>>
>>
>> ...almost all of them (except assignment to rootLogger) by themselves
>> ensure that the state mutations they make are published to other
>> threads, so if also *rootLogger* field was made volatile, such
>> double-checked locking would presumably not be broken.
> Hmmm... By that I assume you mean the operations that access
> LogManager.rootLogger
> from LoggerContext. AFAIR all these operations are synchronized on
> LoggerContext,
The fact that they are synchronized on LoggerContext does not prevent
publication of rootLogger to them without write-read edge, since writing
to rootLogger field is performed without synchronization on the same
LoggerContext (it is performed with synchronization on the LogManager
instance)...
> and will trigger a call to ensureLogManagerInitialized().
> ensureLogManagerInitialized() is called for every add/get logger
> operation.
> If ensureLogManagerInitialized() is executing other threads will be
> blocked.
> When it finishes - threads that were waiting on the monitor will find the
> initializationCalled flag set to true and will simply return.
Ok.
> 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 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