为什么 java.util.logging.Formatter 中的 formatMessage() 方法是同步的?

Why is the formatMessage() method in java.util.logging.Formatter synchronized?

抽象的JDK class Formatter,用于格式化调试日志,formatMessage方法被声明为synchronized。

但是,我无法确定为什么会这样。

显然,可以编写非线程安全的覆盖版本,但我想知道为什么默认实现不是线程安全的。

[T]he formatMessage method is declared as synchronized.However, I haven't been able to determine why that is the case.

java.util.logging.Formatter 的早期版本试图缓存资源包获取字符串调用的结果以避免构建 java.util.MissingResourceException。同步用于保护用于缓存查找的 HashMap

这里是 Copyright 2004 Sun Microsystems, Inc. version 1.16, 12/19/03 源代码,注意注释:

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.

当缓存代码被注释掉时,同步应该被删除。此问题在 JDK-8153666: Possible optimization of Formatter.formatMessage.

下归档

It's definitely synchronized in OpenJDK but perhaps not in the JavaDocs

来自 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.

  1. record.essage 是原始代码中的实际错字。
  2. 注意 record.getMessage() 如何调用多次,即使它在第一次调用时存储在本地。
  3. 该代码允许将空引用传递给 catalog.getString,这将因 NPE 而失败。