In the abstract JDK class Formatter, which is used to format debug logs, the formatMessage method is declared as synchronized.
However, I haven\'t been able to deter
[T]he formatMessage method is declared as synchronized.However, I haven't been able to determine why that is the case.
An early version of java.util.logging.Formatter tried to cache the result of resource bundle get string calls to avoid construction of java.util.MissingResourceException
. Synchronization was used to guard the HashMap
that was used to cache the lookups.
Here is the Copyright 2004 Sun Microsystems, Inc. version 1.16, 12/19/03 source code, note the comments:
public synchronized String formatMessage(LogRecord record) {
String format = record.getMessage();
java.util.ResourceBundle catalog = record.getResourceBundle();
if (catalog != null) {
// We cache catalog lookups. This is mostly to avoid the
// cost of exceptions for keys that are not in the catalog.
// if (catalogCache == null) {
// catalogCache = new HashMap();
// }
// format = (String)catalogCache.get(record.essage);
// if (format == null) {
try {
format = catalog.getString(record.getMessage());
} catch (java.util.MissingResourceException ex) {
// Drop through. Use record message as format
format = record.getMessage();
}
// catalogCache.put(record.message, format);
// }
}
// Do the formatting.
try {
Object parameters[] = record.getParameters();
if (parameters == null || parameters.length == 0) {
// No parameters. Just return format string.
return format;
}
// Is is a java.text style format?
// Ideally we could match with
// Pattern.compile("\\{\\d").matcher(format).find())
// However the cost is 14% higher, so we cheaply check for
// 1 of the first 4 parameters
if (format.indexOf("{0") >= 0 || format.indexOf("{1") >=0 ||
format.indexOf("{2") >=0|| format.indexOf("{3") >=0) {
return java.text.MessageFormat.format(format, parameters);
}
return format;
} catch (Exception ex) {
// Formatting failed: use localized format string.
return format;
}
}
I'm wondering why the default implementation is not thread safe.
When the caching code was commented out the synchronization should have been removed. This issue is filed under JDK-8153666: Possible optimization of Formatter.formatMessage.
It's definitely synchronized in OpenJDK but perhaps not in the JavaDocs
From What's New in Javadoc 1.2:
Remove "synchronized" and "native" from signatures. Javadoc generates an API specification. These two keywords do not belong in the signatures of a specification, because they are implementation-specific. The keyword "native" does not need to be documented. The keyword "synchronized" indicates thread-safe behavior that should instead be described in the method descriptions. A thread-safe method itself might not use the "synchronized" keyword but might call private methods that are.
P.S.
record.essage
is an actual typo from the original code.record.getMessage()
called multiple times even though it is stored in a local on first invocation.catalog.getString
which will fail with an NPE.