src/share/classes/java/util/logging/LogManager.java
Print this page
*** 144,154 ****
public class LogManager {
// The global LogManager object
private static final LogManager manager;
! private Properties props = new Properties();
private final static Level defaultLevel = Level.INFO;
// The map of the registered listeners. The map value is the registration
// count to allow for cases where the same listener is registered many times.
private final Map<Object,Integer> listenerMap = new HashMap<>();
--- 144,161 ----
public class LogManager {
// The global LogManager object
private static final LogManager manager;
! // 'props' is assigned within a lock but accessed without it.
! // Declaring it volatile makes sure that another thread will not
! // be able to see a partially constructed 'props' object.
! // (seeing a partially constructed 'props' object can result in
! // NPE being thrown in Hashtable.get(), because it leaves the door
! // open for props.getProperties() to be called before the construcor
! // of Hashtable is actually completed).
! private volatile Properties props = new Properties();
private final static Level defaultLevel = Level.INFO;
// The map of the registered listeners. The map value is the registration
// count to allow for cases where the same listener is registered many times.
private final Map<Object,Integer> listenerMap = new HashMap<>();
*** 668,678 ****
}
Logger logger = ref.get();
if (logger == null) {
// Hashtable holds stale weak reference
// to a logger which has been GC-ed.
! removeLogger(name);
}
return logger;
}
// This method is called before adding a logger to the
--- 675,685 ----
}
Logger logger = ref.get();
if (logger == null) {
// Hashtable holds stale weak reference
// to a logger which has been GC-ed.
! ref.dispose();
}
return logger;
}
// This method is called before adding a logger to the
*** 754,764 ****
if (ref != null) {
if (ref.get() == null) {
// It's possible that the Logger was GC'ed after a
// drainLoggerRefQueueBounded() call above so allow
// a new one to be registered.
! removeLogger(name);
} else {
// We already have a registered logger with the given name.
return false;
}
}
--- 761,771 ----
if (ref != null) {
if (ref.get() == null) {
// It's possible that the Logger was GC'ed after a
// drainLoggerRefQueueBounded() call above so allow
// a new one to be registered.
! ref.dispose();
} else {
// We already have a registered logger with the given name.
return false;
}
}
*** 806,819 ****
// new LogNode is ready so tell the LoggerWeakRef about it
ref.setNode(node);
return true;
}
! // note: all calls to removeLogger are synchronized on LogManager's
! // intrinsic lock
! void removeLogger(String name) {
! namedLoggers.remove(name);
}
synchronized Enumeration<String> getLoggerNames() {
// ensure that this context is properly initialized before
// returning logger names.
--- 813,824 ----
// new LogNode is ready so tell the LoggerWeakRef about it
ref.setNode(node);
return true;
}
! synchronized void removeLoggerRef(String name, LoggerWeakRef ref) {
! namedLoggers.remove(name, ref);
}
synchronized Enumeration<String> getLoggerNames() {
// ensure that this context is properly initialized before
// returning logger names.
*** 991,1018 ****
//
final class LoggerWeakRef extends WeakReference<Logger> {
private String name; // for namedLoggers cleanup
private LogNode node; // for loggerRef cleanup
private WeakReference<Logger> parentRef; // for kids cleanup
LoggerWeakRef(Logger logger) {
super(logger, loggerRefQueue);
name = logger.getName(); // save for namedLoggers cleanup
}
// dispose of this LoggerWeakRef object
void dispose() {
! if (node != null) {
// if we have a LogNode, then we were a named Logger
// so clear namedLoggers weak ref to us
! node.context.removeLogger(name);
name = null; // clear our ref to the Logger's name
! node.loggerRef = null; // clear LogNode's weak ref to us
node = null; // clear our ref to LogNode
}
if (parentRef != null) {
// this LoggerWeakRef has or had a parent Logger
Logger parent = parentRef.get();
if (parent != null) {
--- 996,1055 ----
//
final class LoggerWeakRef extends WeakReference<Logger> {
private String name; // for namedLoggers cleanup
private LogNode node; // for loggerRef cleanup
private WeakReference<Logger> parentRef; // for kids cleanup
+ private boolean disposed = false; // avoid calling dispose twice
LoggerWeakRef(Logger logger) {
super(logger, loggerRefQueue);
name = logger.getName(); // save for namedLoggers cleanup
}
// dispose of this LoggerWeakRef object
void dispose() {
! // Avoid calling dispose twice. When a Logger is gc'ed, its
! // LoggerWeakRef will be enqueued.
! // However, a new logger of the same name may be added (or looked
! // up) before the queue is drained. When that happens, dispose()
! // will be called by addLocalLogger() or findLogger().
! // Later when the queue is drained, dispose() will be called again
! // for the same LoggerWeakRef. Marking LoggerWeakRef as disposed
! // avoids processing the data twice (even though the code should
! // now be reentrant).
! synchronized(this) {
! // Note to maintainers:
! // Be careful not to call any method that tries to acquire
! // another lock from within this block - as this would surely
! // lead to deadlocks, given that dispose() can be called by
! // multiple threads, and from within different synchronized
! // methods/blocks.
! if (disposed) return;
! disposed = true;
! }
!
! final LogNode n = node;
! if (n != null) {
! // n.loggerRef can only be safely modified from within
! // a lock on LoggerContext. removeLoggerRef is already
! // synchronized on LoggerContext so calling
! // n.context.removeLoggerRef from within this lock is safe.
! synchronized (n.context) {
// if we have a LogNode, then we were a named Logger
// so clear namedLoggers weak ref to us
! n.context.removeLoggerRef(name, this);
name = null; // clear our ref to the Logger's name
! // LogNode may have been reused - so only clear
! // LogNode.loggerRef if LogNode.loggerRef == this
! if (n.loggerRef == this) {
! n.loggerRef = null; // clear LogNode's weak ref to us
! }
node = null; // clear our ref to LogNode
}
+ }
if (parentRef != null) {
// this LoggerWeakRef has or had a parent Logger
Logger parent = parentRef.get();
if (parent != null) {
*** 1060,1070 ****
// - average: 0.57 ms
// - minimum: 0.02 ms
// - maximum: 10.9 ms
//
private final static int MAX_ITERATIONS = 400;
! final synchronized void drainLoggerRefQueueBounded() {
for (int i = 0; i < MAX_ITERATIONS; i++) {
if (loggerRefQueue == null) {
// haven't finished loading LogManager yet
break;
}
--- 1097,1107 ----
// - average: 0.57 ms
// - minimum: 0.02 ms
// - maximum: 10.9 ms
//
private final static int MAX_ITERATIONS = 400;
! final void drainLoggerRefQueueBounded() {
for (int i = 0; i < MAX_ITERATIONS; i++) {
if (loggerRefQueue == null) {
// haven't finished loading LogManager yet
break;
}