OSDN Git Service

libjava/
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / util / logging / Logger.java
index 01ef8f5..f7157c1 100644 (file)
@@ -45,110 +45,105 @@ import java.security.AccessController;
 import java.security.PrivilegedAction;
 
 /**
- * A Logger is used for logging information about events. Usually, there
- * is a seprate logger for each subsystem or component, although there
- * is a shared instance for components that make only occasional use of
- * the logging framework.
- *
- * <p>It is common to name a logger after the name of a corresponding
- * Java package.  Loggers are organized into a hierarchical namespace;
- * for example, the logger <code>"org.gnu.foo"</code> is the
- * <em>parent</em> of logger <code>"org.gnu.foo.bar"</code>.
- *
- * <p>A logger for a named subsystem can be obtained through {@link
- * java.util.logging.Logger#getLogger(java.lang.String)}.  However,
- * only code which has been granted the permission to control the
- * logging infrastructure will be allowed to customize that logger.
- * Untrusted code can obtain a private, anonymous logger through
- * {@link #getAnonymousLogger()} if it wants to perform any
- * modifications to the logger.
- *
- * <p>FIXME: Write more documentation.
- *
+ * A Logger is used for logging information about events. Usually, there is a
+ * seprate logger for each subsystem or component, although there is a shared
+ * instance for components that make only occasional use of the logging
+ * framework.
+ * <p>
+ * It is common to name a logger after the name of a corresponding Java package.
+ * Loggers are organized into a hierarchical namespace; for example, the logger
+ * <code>"org.gnu.foo"</code> is the <em>parent</em> of logger
+ * <code>"org.gnu.foo.bar"</code>.
+ * <p>
+ * A logger for a named subsystem can be obtained through {@link
+ * java.util.logging.Logger#getLogger(java.lang.String)}. However, only code
+ * which has been granted the permission to control the logging infrastructure
+ * will be allowed to customize that logger. Untrusted code can obtain a
+ * private, anonymous logger through {@link #getAnonymousLogger()} if it wants
+ * to perform any modifications to the logger.
+ * <p>
+ * FIXME: Write more documentation.
+ * 
  * @author Sascha Brawer (brawer@acm.org)
  */
 public class Logger
 {
-
   static final Logger root = new Logger("", null);
 
   /**
-   * A logger provided to applications that make only occasional use
-   * of the logging framework, typically early prototypes.  Serious
-   * products are supposed to create and use their own Loggers, so
-   * they can be controlled individually.
+   * A logger provided to applications that make only occasional use of the
+   * logging framework, typically early prototypes. Serious products are
+   * supposed to create and use their own Loggers, so they can be controlled
+   * individually.
    */
   public static final Logger global;
 
+  /**
+   * Use to lock methods on this class instead of calling synchronize on methods
+   * to avoid deadlocks. Yeah, no kidding, we got them :)
+   */
+  private static final Object[] lock = new Object[0];
+  
   static
     {
       // Our class might be initialized from an unprivileged context
-      global = (Logger) AccessController.doPrivileged
-       (new PrivilegedAction()
-         {
-           public Object run()
-           {
-             return getLogger("global");
-           }
-         });
+      global = (Logger) AccessController.doPrivileged(new PrivilegedAction()
+      {
+        public Object run()
+        {
+          return getLogger("global");
+        }
+      });
     }
 
-
   /**
-   * The name of the Logger, or <code>null</code> if the logger is
-   * anonymous.
-   *
-   * <p>A previous version of the GNU Classpath implementation granted
-   * untrusted code the permission to control any logger whose name
-   * was null.  However, test code revealed that the Sun J2SE 1.4
-   * reference implementation enforces the security control for any
-   * logger that was not created through getAnonymousLogger, even if
-   * it has a null name.  Therefore, a separate flag {@link
-   * Logger#anonymous} was introduced.
+   * The name of the Logger, or <code>null</code> if the logger is anonymous.
+   * <p>
+   * A previous version of the GNU Classpath implementation granted untrusted
+   * code the permission to control any logger whose name was null. However,
+   * test code revealed that the Sun J2SE 1.4 reference implementation enforces
+   * the security control for any logger that was not created through
+   * getAnonymousLogger, even if it has a null name. Therefore, a separate flag
+   * {@link Logger#anonymous} was introduced.
    */
   private final String name;
 
-
   /**
    * The name of the resource bundle used for localization.
-   *
-   * <p>This variable cannot be declared as <code>final</code>
-   * because its value can change as a result of calling
-   * getLogger(String,String).
+   * <p>
+   * This variable cannot be declared as <code>final</code> because its value
+   * can change as a result of calling getLogger(String,String).
    */
   private String resourceBundleName;
 
-
   /**
    * The resource bundle used for localization.
-   *
-   * <p>This variable cannot be declared as <code>final</code>
-   * because its value can change as a result of calling
-   * getLogger(String,String).
+   * <p>
+   * This variable cannot be declared as <code>final</code> because its value
+   * can change as a result of calling getLogger(String,String).
    */
   private ResourceBundle resourceBundle;
 
   private Filter filter;
 
   private final List handlerList = new java.util.ArrayList(4);
+
   private Handler[] handlers = new Handler[0];
 
   /**
-   * Indicates whether or not this logger is anonymous.  While
-   * a LoggingPermission is required for any modifications to
-   * a normal logger, untrusted code can obtain an anonymous logger
-   * and modify it according to its needs.
-   *
-   * <p>A previous version of the GNU Classpath implementation
-   * granted access to every logger whose name was null.
-   * However, test code revealed that the Sun J2SE 1.4 reference
-   * implementation enforces the security control for any logger
-   * that was not created through getAnonymousLogger, even
-   * if it has a null name.
+   * Indicates whether or not this logger is anonymous. While a
+   * LoggingPermission is required for any modifications to a normal logger,
+   * untrusted code can obtain an anonymous logger and modify it according to
+   * its needs.
+   * <p>
+   * A previous version of the GNU Classpath implementation granted access to
+   * every logger whose name was null. However, test code revealed that the Sun
+   * J2SE 1.4 reference implementation enforces the security control for any
+   * logger that was not created through getAnonymousLogger, even if it has a
+   * null name.
    */
   private boolean anonymous;
 
-
   private boolean useParentHandlers;
 
   private Level level;
@@ -156,29 +151,26 @@ public class Logger
   private Logger parent;
 
   /**
-   * Constructs a Logger for a subsystem.  Most applications do not
-   * need to create new Loggers explicitly; instead, they should call
-   * the static factory methods
-   * {@link #getLogger(java.lang.String,java.lang.String) getLogger}
+   * Constructs a Logger for a subsystem. Most applications do not need to
+   * create new Loggers explicitly; instead, they should call the static factory
+   * methods {@link #getLogger(java.lang.String,java.lang.String) getLogger}
    * (with ResourceBundle for localization) or
-   * {@link #getLogger(java.lang.String) getLogger} (without
-   * ResourceBundle), respectively.
-   *
-   * @param name the name for the logger, for example "java.awt"
-   *             or "com.foo.bar". The name should be based on
-   *             the name of the package issuing log records
-   *             and consist of dot-separated Java identifiers.
-   *
-   * @param resourceBundleName the name of a resource bundle
-   *        for localizing messages, or <code>null</code>
-   *       to indicate that messages do not need to be localized.
-   *
+   * {@link #getLogger(java.lang.String) getLogger} (without ResourceBundle),
+   * respectively.
+   * 
+   * @param name the name for the logger, for example "java.awt" or
+   *            "com.foo.bar". The name should be based on the name of the
+   *            package issuing log records and consist of dot-separated Java
+   *            identifiers.
+   * @param resourceBundleName the name of a resource bundle for localizing
+   *            messages, or <code>null</code> to indicate that messages do
+   *            not need to be localized.
    * @throws java.util.MissingResourceException if
-   *         <code>resourceBundleName</code> is not <code>null</code>
-   *         and no such bundle could be located.
+   *             <code>resourceBundleName</code> is not <code>null</code>
+   *             and no such bundle could be located.
    */
   protected Logger(String name, String resourceBundleName)
-    throws MissingResourceException
+      throws MissingResourceException
   {
     this.name = name;
     this.resourceBundleName = resourceBundleName;
@@ -190,1002 +182,978 @@ public class Logger
 
     level = null;
 
-    /* This is null when the root logger is being constructed,
-     * and the root logger afterwards.
+    /*
+     * This is null when the root logger is being constructed, and the root
+     * logger afterwards.
      */
     parent = root;
 
     useParentHandlers = (parent != null);
   }
 
-
-
   /**
-   * Finds a registered logger for a subsystem, or creates one in
-   * case no logger has been registered yet.
-   *
-   * @param name the name for the logger, for example "java.awt"
-   *             or "com.foo.bar". The name should be based on
-   *             the name of the package issuing log records
-   *             and consist of dot-separated Java identifiers.
-   *
-   * @throws IllegalArgumentException if a logger for the subsystem
-   *         identified by <code>name</code> has already been created,
-   *         but uses a a resource bundle for localizing messages.
-   *
-   * @throws NullPointerException if <code>name</code> is
-   *         <code>null</code>.
-   *
-   * @return a logger for the subsystem specified by <code>name</code>
-   *         that does not localize messages.
+   * Finds a registered logger for a subsystem, or creates one in case no logger
+   * has been registered yet.
+   * 
+   * @param name the name for the logger, for example "java.awt" or
+   *            "com.foo.bar". The name should be based on the name of the
+   *            package issuing log records and consist of dot-separated Java
+   *            identifiers.
+   * @throws IllegalArgumentException if a logger for the subsystem identified
+   *             by <code>name</code> has already been created, but uses a a
+   *             resource bundle for localizing messages.
+   * @throws NullPointerException if <code>name</code> is <code>null</code>.
+   * @return a logger for the subsystem specified by <code>name</code> that
+   *         does not localize messages.
    */
   public static Logger getLogger(String name)
   {
     return getLogger(name, null);
   }
 
-    
   /**
-   * Finds a registered logger for a subsystem, or creates one in case
-   * no logger has been registered yet.
-   *
-   * <p>If a logger with the specified name has already been
-   * registered, the behavior depends on the resource bundle that is
-   * currently associated with the existing logger.
-   *
-   * <ul><li>If the existing logger uses the same resource bundle as
-   * specified by <code>resourceBundleName</code>, the existing logger
-   * is returned.</li>
-   *
-   * <li>If the existing logger currently does not localize messages,
-   * the existing logger is modified to use the bundle specified by
-   * <code>resourceBundleName</code>.  The existing logger is then
-   * returned.  Therefore, all subsystems currently using this logger
-   * will produce localized messages from now on.</li>
-   *
-   * <li>If the existing logger already has an associated resource
-   * bundle, but a different one than specified by
-   * <code>resourceBundleName</code>, an
-   * <code>IllegalArgumentException</code> is thrown.</li></ul>
-   *
-   * @param name the name for the logger, for example "java.awt"
-   *             or "org.gnu.foo". The name should be based on
-   *             the name of the package issuing log records
-   *             and consist of dot-separated Java identifiers.
-   *
-   * @param resourceBundleName the name of a resource bundle
-   *        for localizing messages, or <code>null</code>
-   *       to indicate that messages do not need to be localized.
-   *
+   * Finds a registered logger for a subsystem, or creates one in case no logger
+   * has been registered yet.
+   * <p>
+   * If a logger with the specified name has already been registered, the
+   * behavior depends on the resource bundle that is currently associated with
+   * the existing logger.
+   * <ul>
+   * <li>If the existing logger uses the same resource bundle as specified by
+   * <code>resourceBundleName</code>, the existing logger is returned.</li>
+   * <li>If the existing logger currently does not localize messages, the
+   * existing logger is modified to use the bundle specified by
+   * <code>resourceBundleName</code>. The existing logger is then returned.
+   * Therefore, all subsystems currently using this logger will produce
+   * localized messages from now on.</li>
+   * <li>If the existing logger already has an associated resource bundle, but
+   * a different one than specified by <code>resourceBundleName</code>, an
+   * <code>IllegalArgumentException</code> is thrown.</li>
+   * </ul>
+   * 
+   * @param name the name for the logger, for example "java.awt" or
+   *            "org.gnu.foo". The name should be based on the name of the
+   *            package issuing log records and consist of dot-separated Java
+   *            identifiers.
+   * @param resourceBundleName the name of a resource bundle for localizing
+   *            messages, or <code>null</code> to indicate that messages do
+   *            not need to be localized.
    * @return a logger for the subsystem specified by <code>name</code>.
-   *
    * @throws java.util.MissingResourceException if
-   *         <code>resourceBundleName</code> is not <code>null</code>
-   *         and no such bundle could be located.   
-   *
-   * @throws IllegalArgumentException if a logger for the subsystem
-   *         identified by <code>name</code> has already been created,
-   *         but uses a different resource bundle for localizing
-   *         messages.
-   *
-   * @throws NullPointerException if <code>name</code> is
-   *         <code>null</code>.
+   *             <code>resourceBundleName</code> is not <code>null</code>
+   *             and no such bundle could be located.
+   * @throws IllegalArgumentException if a logger for the subsystem identified
+   *             by <code>name</code> has already been created, but uses a
+   *             different resource bundle for localizing messages.
+   * @throws NullPointerException if <code>name</code> is <code>null</code>.
    */
   public static Logger getLogger(String name, String resourceBundleName)
   {
     LogManager lm = LogManager.getLogManager();
-    Logger     result;
+    Logger result;
 
     if (name == null)
       throw new NullPointerException();
 
-    /* Without synchronized(lm), it could happen that another thread
-     * would create a logger between our calls to getLogger and
-     * addLogger.  While addLogger would indicate this by returning
-     * false, we could not be sure that this other logger was still
-     * existing when we called getLogger a second time in order
-     * to retrieve it -- note that LogManager is only allowed to
-     * keep weak references to registered loggers, so Loggers
-     * can be garbage collected at any time in general, and between
-     * our call to addLogger and our second call go getLogger
-     * in particular.
-     *
-     * Of course, we assume here that LogManager.addLogger etc.
-     * are synchronizing on the global LogManager object. There
-     * is a comment in the implementation of LogManager.addLogger
-     * referring to this comment here, so that any change in
-     * the synchronization of LogManager will be reflected here.
+    /*
+     * Without synchronized(lm), it could happen that another thread would
+     * create a logger between our calls to getLogger and addLogger. While
+     * addLogger would indicate this by returning false, we could not be sure
+     * that this other logger was still existing when we called getLogger a
+     * second time in order to retrieve it -- note that LogManager is only
+     * allowed to keep weak references to registered loggers, so Loggers can be
+     * garbage collected at any time in general, and between our call to
+     * addLogger and our second call go getLogger in particular. Of course, we
+     * assume here that LogManager.addLogger etc. are synchronizing on the
+     * global LogManager object. There is a comment in the implementation of
+     * LogManager.addLogger referring to this comment here, so that any change
+     * in the synchronization of LogManager will be reflected here.
      */
-    synchronized (lm)
-    {
-      result = lm.getLogger(name);
-      if (result == null)
-      {
-       boolean couldBeAdded;
-
-       result = new Logger(name, resourceBundleName);
-       couldBeAdded = lm.addLogger(result);
-       if (!couldBeAdded)
-         throw new IllegalStateException("cannot register new logger");
-      }
-      else
+    synchronized (lock)
       {
-       /* The logger already exists. Make sure it uses
-        * the same resource bundle for localizing messages.
-        */
-       String existingBundleName = result.getResourceBundleName();
-
-       /* The Sun J2SE 1.4 reference implementation will return the
-        * registered logger object, even if it does not have a resource
-        * bundle associated with it. However, it seems to change the
-        * resourceBundle of the registered logger to the bundle
-        * whose name was passed to getLogger.
-        */
-       if ((existingBundleName == null) && (resourceBundleName != null))
-       {
-         /* If ResourceBundle.getBundle throws an exception, the
-          * existing logger will be unchanged.  This would be
-          * different if the assignment to resourceBundleName
-          * came first.
-          */
-         result.resourceBundle = ResourceBundle.getBundle(resourceBundleName);
-         result.resourceBundleName = resourceBundleName;
-         return result;
-       }
-
-       if ((existingBundleName != resourceBundleName)
-           && ((existingBundleName == null)
-               || !existingBundleName.equals(resourceBundleName)))
-       {
-         throw new IllegalArgumentException();
-       }
+        synchronized (lm)
+          {
+            result = lm.getLogger(name);
+            if (result == null)
+              {
+                boolean couldBeAdded;
+
+                result = new Logger(name, resourceBundleName);
+                couldBeAdded = lm.addLogger(result);
+                if (! couldBeAdded)
+                  throw new IllegalStateException("cannot register new logger");
+              }
+            else
+              {
+                /*
+                 * The logger already exists. Make sure it uses the same
+                 * resource bundle for localizing messages.
+                 */
+                String existingBundleName = result.getResourceBundleName();
+
+                /*
+                 * The Sun J2SE 1.4 reference implementation will return the
+                 * registered logger object, even if it does not have a resource
+                 * bundle associated with it. However, it seems to change the
+                 * resourceBundle of the registered logger to the bundle whose
+                 * name was passed to getLogger.
+                 */
+                if ((existingBundleName == null) &&
+                    (resourceBundleName != null))
+                  {
+                    /*
+                     * If ResourceBundle.getBundle throws an exception, the
+                     * existing logger will be unchanged. This would be
+                     * different if the assignment to resourceBundleName came
+                     * first.
+                     */
+                    result.resourceBundle =
+                      ResourceBundle.getBundle(resourceBundleName);
+
+                    result.resourceBundleName = resourceBundleName;
+                    return result;
+                  }
+
+                if ((existingBundleName != resourceBundleName)
+                    && ((existingBundleName == null)
+                        || !existingBundleName.equals(resourceBundleName)))
+                  {
+                    throw new IllegalArgumentException();
+                  }
+              }
+          }
       }
-    }
 
     return result;
   }
 
-  
   /**
-   * Creates a new, unnamed logger.  Unnamed loggers are not
-   * registered in the namespace of the LogManager, and no special
-   * security permission is required for changing their state.
-   * Therefore, untrusted applets are able to modify their private
-   * logger instance obtained through this method.
-   *
-   * <p>The parent of the newly created logger will the the root
-   * logger, from which the level threshold and the handlers are
-   * inherited.
+   * Creates a new, unnamed logger. Unnamed loggers are not registered in the
+   * namespace of the LogManager, and no special security permission is required
+   * for changing their state. Therefore, untrusted applets are able to modify
+   * their private logger instance obtained through this method.
+   * <p>
+   * The parent of the newly created logger will the the root logger, from which
+   * the level threshold and the handlers are inherited.
    */
   public static Logger getAnonymousLogger()
   {
     return getAnonymousLogger(null);
   }
 
-
   /**
-   * Creates a new, unnamed logger.  Unnamed loggers are not
-   * registered in the namespace of the LogManager, and no special
-   * security permission is required for changing their state.
-   * Therefore, untrusted applets are able to modify their private
-   * logger instance obtained through this method.
-   *
-   * <p>The parent of the newly created logger will the the root
-   * logger, from which the level threshold and the handlers are
-   * inherited.
-   *
-   * @param resourceBundleName the name of a resource bundle
-   *        for localizing messages, or <code>null</code>
-   *       to indicate that messages do not need to be localized.
-   *
+   * Creates a new, unnamed logger. Unnamed loggers are not registered in the
+   * namespace of the LogManager, and no special security permission is required
+   * for changing their state. Therefore, untrusted applets are able to modify
+   * their private logger instance obtained through this method.
+   * <p>
+   * The parent of the newly created logger will the the root logger, from which
+   * the level threshold and the handlers are inherited.
+   * 
+   * @param resourceBundleName the name of a resource bundle for localizing
+   *            messages, or <code>null</code> to indicate that messages do
+   *            not need to be localized.
    * @throws java.util.MissingResourceException if
-   *         <code>resourceBundleName</code> is not <code>null</code>
-   *         and no such bundle could be located.
+   *             <code>resourceBundleName</code> is not <code>null</code>
+   *             and no such bundle could be located.
    */
   public static Logger getAnonymousLogger(String resourceBundleName)
-    throws MissingResourceException
+      throws MissingResourceException
   {
-    Logger  result;
+    Logger result;
 
     result = new Logger(null, resourceBundleName);
     result.anonymous = true;
     return result;
   }
 
-
   /**
-   * Returns the name of the resource bundle that is being used for
-   * localizing messages.
-   *
-   * @return the name of the resource bundle used for localizing messages,
-   *         or <code>null</code> if the parent's resource bundle
-   *         is used for this purpose.
+   * Returns the name of the resource bundle that is being used for localizing
+   * messages.
+   * 
+   * @return the name of the resource bundle used for localizing messages, or
+   *         <code>null</code> if the parent's resource bundle is used for
+   *         this purpose.
    */
-  public synchronized String getResourceBundleName()
+  public String getResourceBundleName()
   {
-    return resourceBundleName;
+    synchronized (lock)
+      {
+        return resourceBundleName;
+      }
   }
 
-
   /**
-   * Returns the resource bundle that is being used for localizing
-   * messages.
-   *
-   * @return the resource bundle used for localizing messages,
-   *         or <code>null</code> if the parent's resource bundle
-   *         is used for this purpose.
+   * Returns the resource bundle that is being used for localizing messages.
+   * 
+   * @return the resource bundle used for localizing messages, or
+   *         <code>null</code> if the parent's resource bundle is used for
+   *         this purpose.
    */
-  public synchronized ResourceBundle getResourceBundle()
+  public ResourceBundle getResourceBundle()
   {
-    return resourceBundle;
+    synchronized (lock)
+      {
+        return resourceBundle;
+      }
   }
 
-
   /**
-   * Returns the severity level threshold for this <code>Handler</code>.
-   * All log records with a lower severity level will be discarded;
-   * a log record of the same or a higher level will be published
-   * unless an installed <code>Filter</code> decides to discard it.
-   *
-   * @return the severity level below which all log messages will be
-   *         discarded, or <code>null</code> if the logger inherits
-   *         the threshold from its parent.
+   * Returns the severity level threshold for this <code>Handler</code>. All
+   * log records with a lower severity level will be discarded; a log record of
+   * the same or a higher level will be published unless an installed
+   * <code>Filter</code> decides to discard it.
+   * 
+   * @return the severity level below which all log messages will be discarded,
+   *         or <code>null</code> if the logger inherits the threshold from
+   *         its parent.
    */
-  public synchronized Level getLevel()
+  public Level getLevel()
   {
-    return level;
+    synchronized (lock)
+      {
+        return level;
+      }
   }
 
-
   /**
-   * Returns whether or not a message of the specified level
-   * would be logged by this logger.
-   *
-   * @throws NullPointerException if <code>level</code>
-   *         is <code>null</code>.
+   * Returns whether or not a message of the specified level would be logged by
+   * this logger.
+   * 
+   * @throws NullPointerException if <code>level</code> is <code>null</code>.
    */
-  public synchronized boolean isLoggable(Level level)
+  public boolean isLoggable(Level level)
   {
-    if (this.level != null)
-      return this.level.intValue() <= level.intValue();
+    synchronized (lock)
+      {
+        if (this.level != null)
+          return this.level.intValue() <= level.intValue();
 
-    if (parent != null)
-      return parent.isLoggable(level);
-    else
-      return false;
+        if (parent != null)
+          return parent.isLoggable(level);
+        else
+          return false;
+      }
   }
 
-
   /**
-   * Sets the severity level threshold for this <code>Handler</code>.
-   * All log records with a lower severity level will be discarded
-   * immediately.  A log record of the same or a higher level will be
-   * published unless an installed <code>Filter</code> decides to
-   * discard it.
-   *
-   * @param level the severity level below which all log messages
-   *              will be discarded, or <code>null</code> to
-   *              indicate that the logger should inherit the
-   *              threshold from its parent.
-   *
-   * @throws SecurityException if this logger is not anonymous, a
-   *     security manager exists, and the caller is not granted
-   *     the permission to control the logging infrastructure by
-   *     having LoggingPermission("control").  Untrusted code can
-   *     obtain an anonymous logger through the static factory method
-   *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
+   * Sets the severity level threshold for this <code>Handler</code>. All log
+   * records with a lower severity level will be discarded immediately. A log
+   * record of the same or a higher level will be published unless an installed
+   * <code>Filter</code> decides to discard it.
+   * 
+   * @param level the severity level below which all log messages will be
+   *            discarded, or <code>null</code> to indicate that the logger
+   *            should inherit the threshold from its parent.
+   * @throws SecurityException if this logger is not anonymous, a security
+   *             manager exists, and the caller is not granted the permission to
+   *             control the logging infrastructure by having
+   *             LoggingPermission("control"). Untrusted code can obtain an
+   *             anonymous logger through the static factory method
+   *             {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
    */
-  public synchronized void setLevel(Level level)
+  public void setLevel(Level level)
   {
-    /* An application is allowed to control an anonymous logger
-     * without having the permission to control the logging
-     * infrastructure.
-     */
-    if (!anonymous)
-      LogManager.getLogManager().checkAccess();
-
-    this.level = level;
+    synchronized (lock)
+      {
+        /*
+         * An application is allowed to control an anonymous logger without
+         * having the permission to control the logging infrastructure.
+         */
+        if (! anonymous)
+          LogManager.getLogManager().checkAccess();
+
+        this.level = level;
+      }
   }
 
-
-  public synchronized Filter getFilter()
+  public Filter getFilter()
   {
-    return filter;
+    synchronized (lock)
+      {
+        return filter;
+      }
   }
 
-
   /**
-   * @throws SecurityException if this logger is not anonymous, a
-   *     security manager exists, and the caller is not granted
-   *     the permission to control the logging infrastructure by
-   *     having LoggingPermission("control").  Untrusted code can
-   *     obtain an anonymous logger through the static factory method
-   *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
+   * @throws SecurityException if this logger is not anonymous, a security
+   *             manager exists, and the caller is not granted the permission to
+   *             control the logging infrastructure by having
+   *             LoggingPermission("control"). Untrusted code can obtain an
+   *             anonymous logger through the static factory method
+   *             {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
    */
-  public synchronized void setFilter(Filter filter)
-    throws SecurityException
+  public void setFilter(Filter filter) throws SecurityException
   {
-    /* An application is allowed to control an anonymous logger
-     * without having the permission to control the logging
-     * infrastructure.
-     */
-    if (!anonymous)
-      LogManager.getLogManager().checkAccess();
-
-    this.filter = filter;
+    synchronized (lock)
+      {
+        /*
+         * An application is allowed to control an anonymous logger without
+         * having the permission to control the logging infrastructure.
+         */
+        if (! anonymous)
+          LogManager.getLogManager().checkAccess();
+
+        this.filter = filter;
+      }
   }
 
-
-
-
   /**
    * Returns the name of this logger.
-   *
-   * @return the name of this logger, or <code>null</code> if
-   *         the logger is anonymous.
+   * 
+   * @return the name of this logger, or <code>null</code> if the logger is
+   *         anonymous.
    */
   public String getName()
   {
-    /* Note that the name of a logger cannot be changed during
-     * its lifetime, so no synchronization is needed.
+    /*
+     * Note that the name of a logger cannot be changed during its lifetime, so
+     * no synchronization is needed.
      */
     return name;
   }
 
-
   /**
-   * Passes a record to registered handlers, provided the record
-   * is considered as loggable both by {@link #isLoggable(Level)}
-   * and a possibly installed custom {@link #setFilter(Filter) filter}.
-   *
-   * <p>If the logger has been configured to use parent handlers,
-   * the record will be forwarded to the parent of this logger
-   * in addition to being processed by the handlers registered with
-   * this logger.
-   *
-   * <p>The other logging methods in this class are convenience methods
-   * that merely create a new LogRecord and pass it to this method.
-   * Therefore, subclasses usually just need to override this single
-   * method for customizing the logging behavior.
-   *
+   * Passes a record to registered handlers, provided the record is considered
+   * as loggable both by {@link #isLoggable(Level)} and a possibly installed
+   * custom {@link #setFilter(Filter) filter}.
+   * <p>
+   * If the logger has been configured to use parent handlers, the record will
+   * be forwarded to the parent of this logger in addition to being processed by
+   * the handlers registered with this logger.
+   * <p>
+   * The other logging methods in this class are convenience methods that merely
+   * create a new LogRecord and pass it to this method. Therefore, subclasses
+   * usually just need to override this single method for customizing the
+   * logging behavior.
+   * 
    * @param record the log record to be inspected and possibly forwarded.
    */
-  public synchronized void log(LogRecord record)
+  public void log(LogRecord record)
   {
-    if (!isLoggable(record.getLevel()))
-      return;
-
-    if ((filter != null) && !filter.isLoggable(record))
-      return;
-
-    /* If no logger name has been set for the log record,
-     * use the name of this logger.
-     */
-    if (record.getLoggerName() == null)
-      record.setLoggerName(name);
-
-    /* Avoid that some other thread is changing the logger hierarchy
-     * while we are traversing it.
-     */
-    synchronized (LogManager.getLogManager())
-    {
-      Logger curLogger = this;
-
-      do
+    synchronized (lock)
       {
-        /* The Sun J2SE 1.4 reference implementation seems to call the
-        * filter only for the logger whose log method is called,
-        * never for any of its parents.  Also, parent loggers publish
-        * log record whatever their level might be.  This is pretty
-        * weird, but GNU Classpath tries to be as compatible as
-        * possible to the reference implementation.
-        */
-        for (int i = 0; i < curLogger.handlers.length; i++)
-          curLogger.handlers[i].publish(record);
-
-       if (curLogger.getUseParentHandlers() == false)
-         break;
-       
-       curLogger = curLogger.getParent();
+        if (!isLoggable(record.getLevel()))
+          return;
+
+        if ((filter != null) && ! filter.isLoggable(record))
+          return;
+
+        /*
+         * If no logger name has been set for the log record, use the name of
+         * this logger.
+         */
+        if (record.getLoggerName() == null)
+          record.setLoggerName(name);
+
+        /*
+         * Avoid that some other thread is changing the logger hierarchy while
+         * we are traversing it.
+         */
+        synchronized (LogManager.getLogManager())
+          {
+            Logger curLogger = this;
+
+            do
+              {
+                /*
+                 * The Sun J2SE 1.4 reference implementation seems to call the
+                 * filter only for the logger whose log method is called, never
+                 * for any of its parents. Also, parent loggers publish log
+                 * record whatever their level might be. This is pretty weird,
+                 * but GNU Classpath tries to be as compatible as possible to
+                 * the reference implementation.
+                 */
+                for (int i = 0; i < curLogger.handlers.length; i++)
+                  curLogger.handlers[i].publish(record);
+
+                if (curLogger.getUseParentHandlers() == false)
+                  break;
+
+                curLogger = curLogger.getParent();
+              }
+            while (parent != null);
+          }
       }
-      while (parent != null);
-    }
   }
 
-
   public void log(Level level, String message)
   {
     if (isLoggable(level))
       log(level, message, (Object[]) null);
   }
 
-
-  public synchronized void log(Level level,
-                              String message,
-                              Object param)
+  public void log(Level level, String message, Object param)
   {
-    if (isLoggable(level))
+    synchronized (lock)
       {
-        StackTraceElement caller = getCallerStackFrame();
-        logp(level,
-             caller != null ? caller.getClassName() : "<unknown>",
-             caller != null ? caller.getMethodName() : "<unknown>",
-             message,
-             param);
+        if (isLoggable(level))
+          {
+            StackTraceElement caller = getCallerStackFrame();
+            logp(level, caller != null ? caller.getClassName() : "<unknown>",
+                 caller != null ? caller.getMethodName() : "<unknown>",
+                 message, param);
+          }
       }
   }
 
-
-  public synchronized void log(Level level,
-                              String message,
-                              Object[] params)
+  public void log(Level level, String message, Object[] params)
   {
-    if (isLoggable(level))
+    synchronized (lock)
       {
-        StackTraceElement caller = getCallerStackFrame();
-        logp(level,
-             caller != null ? caller.getClassName() : "<unknown>",
-             caller != null ? caller.getMethodName() : "<unknown>",
-             message,
-             params);
+        if (isLoggable(level))
+          {
+            StackTraceElement caller = getCallerStackFrame();
+            logp(level, caller != null ? caller.getClassName() : "<unknown>",
+                 caller != null ? caller.getMethodName() : "<unknown>",
+                 message, params);
+
+          }
       }
   }
 
-
-  public synchronized void log(Level level,
-                              String message,
-                              Throwable thrown)
+  public void log(Level level, String message, Throwable thrown)
   {
-    if (isLoggable(level))
+    synchronized (lock)
       {
-        StackTraceElement caller = getCallerStackFrame();    
-        logp(level,
-             caller != null ? caller.getClassName() : "<unknown>",
-             caller != null ? caller.getMethodName() : "<unknown>",
-             message,
-             thrown);
+        if (isLoggable(level))
+          {
+            StackTraceElement caller = getCallerStackFrame();
+            logp(level, caller != null ? caller.getClassName() : "<unknown>",
+                 caller != null ? caller.getMethodName() : "<unknown>",
+                 message, thrown);
+          }
       }
   }
 
-
-  public synchronized void logp(Level level,
-                               String sourceClass,
-                               String sourceMethod,
-                               String message)
+  public void logp(Level level, String sourceClass, String sourceMethod,
+                   String message)
   {
-    logp(level, sourceClass, sourceMethod, message,
-        (Object[]) null);
+    synchronized (lock)
+      {
+        logp(level, sourceClass, sourceMethod, message, (Object[]) null);
+      }
   }
 
-
-  public synchronized void logp(Level level,
-                               String sourceClass,
-                               String sourceMethod,
-                               String message,
-                               Object param)
+  public void logp(Level level, String sourceClass, String sourceMethod,
+                   String message, Object param)
   {
-    logp(level, sourceClass, sourceMethod, message,
-        new Object[] { param });
-  }
+    synchronized (lock)
+      {
+        logp(level, sourceClass, sourceMethod, message, new Object[] { param });
+      }
 
+  }
 
-  private synchronized ResourceBundle findResourceBundle()
+  private ResourceBundle findResourceBundle()
   {
-    if (resourceBundle != null)
-      return resourceBundle;
+    synchronized (lock)
+      {
+        if (resourceBundle != null)
+          return resourceBundle;
 
-    if (parent != null)
-      return parent.findResourceBundle();
+        if (parent != null)
+          return parent.findResourceBundle();
 
-    return null;
+        return null;
+      }
   }
 
-
-  private synchronized void logImpl(Level level,
-                                   String sourceClass,
-                                   String sourceMethod,
-                                   String message,
-                                   Object[] params)
+  private void logImpl(Level level, String sourceClass, String sourceMethod,
+                       String message, Object[] params)
   {
-    LogRecord rec = new LogRecord(level, message);
+    synchronized (lock)
+      {
+        LogRecord rec = new LogRecord(level, message);
 
-    rec.setResourceBundle(findResourceBundle());
-    rec.setSourceClassName(sourceClass);
-    rec.setSourceMethodName(sourceMethod);
-    rec.setParameters(params);
+        rec.setResourceBundle(findResourceBundle());
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setParameters(params);
 
-    log(rec);
+        log(rec);
+      }
   }
 
-
-  public synchronized void logp(Level level,
-                               String sourceClass,
-                               String sourceMethod,
-                               String message,
-                               Object[] params)
+  public void logp(Level level, String sourceClass, String sourceMethod,
+                   String message, Object[] params)
   {
-    logImpl(level, sourceClass, sourceMethod, message, params);
+    synchronized (lock)
+      {
+        logImpl(level, sourceClass, sourceMethod, message, params);
+      }
   }
 
-
-  public synchronized void logp(Level level,
-                               String sourceClass,
-                               String sourceMethod,
-                               String message,
-                               Throwable thrown)
+  public void logp(Level level, String sourceClass, String sourceMethod,
+                   String message, Throwable thrown)
   {
-    LogRecord rec = new LogRecord(level, message);
+    synchronized (lock)
+      {
+        LogRecord rec = new LogRecord(level, message);
 
-    rec.setResourceBundle(resourceBundle);
-    rec.setSourceClassName(sourceClass);
-    rec.setSourceMethodName(sourceMethod);
-    rec.setThrown(thrown);
+        rec.setResourceBundle(resourceBundle);
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setThrown(thrown);
 
-    log(rec);
+        log(rec);
+      }
   }
 
-
-  public synchronized void logrb(Level level,
-                                String sourceClass,
-                                String sourceMethod,
-                                String bundleName,
-                                String message)
+  public void logrb(Level level, String sourceClass, String sourceMethod,
+                    String bundleName, String message)
   {
-    logrb(level, sourceClass, sourceMethod, bundleName,
-         message, (Object[]) null);
+    synchronized (lock)
+      {
+        logrb(level, sourceClass, sourceMethod, bundleName, message,
+              (Object[]) null);
+      }
   }
 
-
-  public synchronized void logrb(Level level,
-                                String sourceClass,
-                                String sourceMethod,
-                                String bundleName,
-                                String message,
-                                Object param)
+  public void logrb(Level level, String sourceClass, String sourceMethod,
+                    String bundleName, String message, Object param)
   {
-    logrb(level, sourceClass, sourceMethod, bundleName,
-         message, new Object[] { param });
+    synchronized (lock)
+      {
+        logrb(level, sourceClass, sourceMethod, bundleName, message,
+              new Object[] { param });
+      }
   }
 
-
-  public synchronized void logrb(Level level,
-                                String sourceClass,
-                                String sourceMethod,
-                                String bundleName,
-                                String message,
-                                Object[] params)
+  public void logrb(Level level, String sourceClass, String sourceMethod,
+                    String bundleName, String message, Object[] params)
   {
-    LogRecord rec = new LogRecord(level, message);
+    synchronized (lock)
+      {
+        LogRecord rec = new LogRecord(level, message);
 
-    rec.setResourceBundleName(bundleName);
-    rec.setSourceClassName(sourceClass);
-    rec.setSourceMethodName(sourceMethod);
-    rec.setParameters(params);
+        rec.setResourceBundleName(bundleName);
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setParameters(params);
 
-    log(rec);
+        log(rec);
+      }
   }
 
-
-  public synchronized void logrb(Level level,
-                                String sourceClass,
-                                String sourceMethod,
-                                String bundleName,
-                                String message,
-                                Throwable thrown)
+  public void logrb(Level level, String sourceClass, String sourceMethod,
+                    String bundleName, String message, Throwable thrown)
   {
-    LogRecord rec = new LogRecord(level, message);
+    synchronized (lock)
+      {
+        LogRecord rec = new LogRecord(level, message);
 
-    rec.setResourceBundleName(bundleName);
-    rec.setSourceClassName(sourceClass);
-    rec.setSourceMethodName(sourceMethod);
-    rec.setThrown(thrown);
+        rec.setResourceBundleName(bundleName);
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setThrown(thrown);
 
-    log(rec);
+        log(rec);
+      }
   }
 
-
-  public synchronized void entering(String sourceClass,
-                                   String sourceMethod)
+  public void entering(String sourceClass, String sourceMethod)
   {
-    if (isLoggable(Level.FINER))
-      logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
+    synchronized (lock)
+      {
+        if (isLoggable(Level.FINER))
+          logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
+      }
   }
 
-
-  public synchronized void entering(String sourceClass,
-                                   String sourceMethod,
-                                   Object param)
+  public void entering(String sourceClass, String sourceMethod, Object param)
   {
-    if (isLoggable(Level.FINER))
-      logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param);
+    synchronized (lock)
+      {
+        if (isLoggable(Level.FINER))
+          logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param);
+      }
   }
 
-
-  public synchronized void entering(String sourceClass,
-                                   String sourceMethod,
-                                   Object[] params)
+  public void entering(String sourceClass, String sourceMethod, Object[] params)
   {
-    if (isLoggable(Level.FINER))
-    {
-      StringBuffer buf = new StringBuffer(80);
-      buf.append("ENTRY");
-      for (int i = 0; i < params.length; i++)
+    synchronized (lock)
       {
-       buf.append(" {");
-       buf.append(i);
-       buf.append('}');
+        if (isLoggable(Level.FINER))
+          {
+            StringBuffer buf = new StringBuffer(80);
+            buf.append("ENTRY");
+            for (int i = 0; i < params.length; i++)
+              {
+                buf.append(" {");
+                buf.append(i);
+                buf.append('}');
+              }
+
+            logp(Level.FINER, sourceClass, sourceMethod, buf.toString(), params);
+          }
       }
-      
-      logp(Level.FINER, sourceClass, sourceMethod, buf.toString(), params);
-    }
   }
 
-
-  public synchronized void exiting(String sourceClass,
-                                  String sourceMethod)
+  public void exiting(String sourceClass, String sourceMethod)
   {
-    if (isLoggable(Level.FINER))
-      logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
+    synchronized (lock)
+      {
+        if (isLoggable(Level.FINER))
+          logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
+      }
   }
 
-   
-  public synchronized void exiting(String sourceClass,
-                                  String sourceMethod,
-                                  Object result)
+  public void exiting(String sourceClass, String sourceMethod, Object result)
   {
-    if (isLoggable(Level.FINER))
-      logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
+    synchronized (lock)
+      {
+        if (isLoggable(Level.FINER))
+          logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
+      }
   }
 
-  public synchronized void throwing(String sourceClass,
-                                   String sourceMethod,
-                                   Throwable thrown)
+  public void throwing(String sourceClass, String sourceMethod, Throwable thrown)
   {
-    if (isLoggable(Level.FINER))
-      logp(Level.FINER, sourceClass, sourceMethod, "THROW", thrown);
+    synchronized (lock)
+      {
+        if (isLoggable(Level.FINER))
+          logp(Level.FINER, sourceClass, sourceMethod, "THROW", thrown);
+      }
   }
 
-
   /**
-   * Logs a message with severity level SEVERE, indicating a serious
-   * failure that prevents normal program execution.  Messages at this
-   * level should be understandable to an inexperienced, non-technical
-   * end user.  Ideally, they explain in simple words what actions the
-   * user can take in order to resolve the problem.
-   *
+   * Logs a message with severity level SEVERE, indicating a serious failure
+   * that prevents normal program execution. Messages at this level should be
+   * understandable to an inexperienced, non-technical end user. Ideally, they
+   * explain in simple words what actions the user can take in order to resolve
+   * the problem.
+   * 
    * @see Level#SEVERE
-   *
-   * @param message the message text, also used as look-up key if the
-   *                logger is localizing messages with a resource
-   *                bundle.  While it is possible to pass
-   *                <code>null</code>, this is not recommended, since
-   *                a logging message without text is unlikely to be
-   *                helpful.
+   * @param message the message text, also used as look-up key if the logger is
+   *            localizing messages with a resource bundle. While it is possible
+   *            to pass <code>null</code>, this is not recommended, since a
+   *            logging message without text is unlikely to be helpful.
    */
-  public synchronized void severe(String message)
+  public void severe(String message)
   {
-    if (isLoggable(Level.SEVERE))
-      log(Level.SEVERE, message);
+    synchronized (lock)
+      {
+        if (isLoggable(Level.SEVERE))
+          log(Level.SEVERE, message);
+      }
   }
 
-
   /**
-   * Logs a message with severity level WARNING, indicating a
-   * potential problem that does not prevent normal program execution.
-   * Messages at this level should be understandable to an
-   * inexperienced, non-technical end user.  Ideally, they explain in
-   * simple words what actions the user can take in order to resolve
-   * the problem.
-   *
+   * Logs a message with severity level WARNING, indicating a potential problem
+   * that does not prevent normal program execution. Messages at this level
+   * should be understandable to an inexperienced, non-technical end user.
+   * Ideally, they explain in simple words what actions the user can take in
+   * order to resolve the problem.
+   * 
    * @see Level#WARNING
-   *
-   * @param message the message text, also used as look-up key if the
-   *                logger is localizing messages with a resource
-   *                bundle.  While it is possible to pass
-   *                <code>null</code>, this is not recommended, since
-   *                a logging message without text is unlikely to be
-   *                helpful.
+   * @param message the message text, also used as look-up key if the logger is
+   *            localizing messages with a resource bundle. While it is possible
+   *            to pass <code>null</code>, this is not recommended, since a
+   *            logging message without text is unlikely to be helpful.
    */
-  public synchronized void warning(String message)
+  public void warning(String message)
   {
-    if (isLoggable(Level.WARNING))
-      log(Level.WARNING, message);
+    synchronized (lock)
+      {
+        if (isLoggable(Level.WARNING))
+          log(Level.WARNING, message);
+      }
   }
 
-
   /**
-   * Logs a message with severity level INFO.  {@link Level#INFO} is
-   * intended for purely informational messages that do not indicate
-   * error or warning situations. In the default logging
-   * configuration, INFO messages will be written to the system
-   * console.  For this reason, the INFO level should be used only for
-   * messages that are important to end users and system
-   * administrators.  Messages at this level should be understandable
-   * to an inexperienced, non-technical user.
-   *
-   * @param message the message text, also used as look-up key if the
-   *                logger is localizing messages with a resource
-   *                bundle.  While it is possible to pass
-   *                <code>null</code>, this is not recommended, since
-   *                a logging message without text is unlikely to be
-   *                helpful.
+   * Logs a message with severity level INFO. {@link Level#INFO} is intended for
+   * purely informational messages that do not indicate error or warning
+   * situations. In the default logging configuration, INFO messages will be
+   * written to the system console. For this reason, the INFO level should be
+   * used only for messages that are important to end users and system
+   * administrators. Messages at this level should be understandable to an
+   * inexperienced, non-technical user.
+   * 
+   * @param message the message text, also used as look-up key if the logger is
+   *            localizing messages with a resource bundle. While it is possible
+   *            to pass <code>null</code>, this is not recommended, since a
+   *            logging message without text is unlikely to be helpful.
    */
-  public synchronized void info(String message)
+  public void info(String message)
   {
-    if (isLoggable(Level.INFO))
-      log(Level.INFO, message);
+    synchronized (lock)
+      {
+        if (isLoggable(Level.INFO))
+          log(Level.INFO, message);
+      }
   }
 
-
   /**
-   * Logs a message with severity level CONFIG.  {@link Level#CONFIG} is
-   * intended for static configuration messages, for example about the
-   * windowing environment, the operating system version, etc.
-   *
-   * @param message the message text, also used as look-up key if the
-   *     logger is localizing messages with a resource bundle.  While
-   *     it is possible to pass <code>null</code>, this is not
-   *     recommended, since a logging message without text is unlikely
-   *     to be helpful.
+   * Logs a message with severity level CONFIG. {@link Level#CONFIG} is intended
+   * for static configuration messages, for example about the windowing
+   * environment, the operating system version, etc.
+   * 
+   * @param message the message text, also used as look-up key if the logger is
+   *            localizing messages with a resource bundle. While it is possible
+   *            to pass <code>null</code>, this is not recommended, since a
+   *            logging message without text is unlikely to be helpful.
    */
-  public synchronized void config(String message)
+  public void config(String message)
   {
-    if (isLoggable(Level.CONFIG))
-      log(Level.CONFIG, message);
+    synchronized (lock)
+      {
+        if (isLoggable(Level.CONFIG))
+          log(Level.CONFIG, message);
+      }
   }
 
-
   /**
-   * Logs a message with severity level FINE.  {@link Level#FINE} is
-   * intended for messages that are relevant for developers using
-   * the component generating log messages. Examples include minor,
-   * recoverable failures, or possible inefficiencies.
-   *
-   * @param message the message text, also used as look-up key if the
-   *                logger is localizing messages with a resource
-   *                bundle.  While it is possible to pass
-   *                <code>null</code>, this is not recommended, since
-   *                a logging message without text is unlikely to be
-   *                helpful.
+   * Logs a message with severity level FINE. {@link Level#FINE} is intended for
+   * messages that are relevant for developers using the component generating
+   * log messages. Examples include minor, recoverable failures, or possible
+   * inefficiencies.
+   * 
+   * @param message the message text, also used as look-up key if the logger is
+   *            localizing messages with a resource bundle. While it is possible
+   *            to pass <code>null</code>, this is not recommended, since a
+   *            logging message without text is unlikely to be helpful.
    */
-  public synchronized void fine(String message)
+  public void fine(String message)
   {
-    if (isLoggable(Level.FINE))
-      log(Level.FINE, message);
+    synchronized (lock)
+      {
+        if (isLoggable(Level.FINE))
+          log(Level.FINE, message);
+      }
   }
 
-
   /**
-   * Logs a message with severity level FINER.  {@link Level#FINER} is
-   * intended for rather detailed tracing, for example entering a
-   * method, returning from a method, or throwing an exception.
-   *
-   * @param message the message text, also used as look-up key if the
-   *                logger is localizing messages with a resource
-   *                bundle.  While it is possible to pass
-   *                <code>null</code>, this is not recommended, since
-   *                a logging message without text is unlikely to be
-   *                helpful.
+   * Logs a message with severity level FINER. {@link Level#FINER} is intended
+   * for rather detailed tracing, for example entering a method, returning from
+   * a method, or throwing an exception.
+   * 
+   * @param message the message text, also used as look-up key if the logger is
+   *            localizing messages with a resource bundle. While it is possible
+   *            to pass <code>null</code>, this is not recommended, since a
+   *            logging message without text is unlikely to be helpful.
    */
-  public synchronized void finer(String message)
+  public void finer(String message)
   {
-    if (isLoggable(Level.FINER))
-      log(Level.FINER, message);
+    synchronized (lock)
+      {
+        if (isLoggable(Level.FINER))
+          log(Level.FINER, message);
+      }
   }
 
-
   /**
-   * Logs a message with severity level FINEST.  {@link Level#FINEST}
-   * is intended for highly detailed tracing, for example reaching a
-   * certain point inside the body of a method.
-   *
-   * @param message the message text, also used as look-up key if the
-   *                logger is localizing messages with a resource
-   *                bundle.  While it is possible to pass
-   *                <code>null</code>, this is not recommended, since
-   *                a logging message without text is unlikely to be
-   *                helpful.
+   * Logs a message with severity level FINEST. {@link Level#FINEST} is intended
+   * for highly detailed tracing, for example reaching a certain point inside
+   * the body of a method.
+   * 
+   * @param message the message text, also used as look-up key if the logger is
+   *            localizing messages with a resource bundle. While it is possible
+   *            to pass <code>null</code>, this is not recommended, since a
+   *            logging message without text is unlikely to be helpful.
    */
-  public synchronized void finest(String message)
+  public void finest(String message)
   {
-    if (isLoggable(Level.FINEST))
-      log(Level.FINEST, message);
+    synchronized (lock)
+      {
+        if (isLoggable(Level.FINEST))
+          log(Level.FINEST, message);
+      }
   }
 
-
   /**
-   * Adds a handler to the set of handlers that get notified
-   * when a log record is to be published.
-   *
+   * Adds a handler to the set of handlers that get notified when a log record
+   * is to be published.
+   * 
    * @param handler the handler to be added.
-   *
-   * @throws NullPointerException if <code>handler</code>
-   *     is <code>null</code>.
-   *
-   * @throws SecurityException if this logger is not anonymous, a
-   *     security manager exists, and the caller is not granted
-   *     the permission to control the logging infrastructure by
-   *     having LoggingPermission("control").  Untrusted code can
-   *     obtain an anonymous logger through the static factory method
-   *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
+   * @throws NullPointerException if <code>handler</code> is <code>null</code>.
+   * @throws SecurityException if this logger is not anonymous, a security
+   *             manager exists, and the caller is not granted the permission to
+   *             control the logging infrastructure by having
+   *             LoggingPermission("control"). Untrusted code can obtain an
+   *             anonymous logger through the static factory method
+   *             {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
    */
-  public synchronized void addHandler(Handler handler)
-    throws SecurityException
+  public void addHandler(Handler handler) throws SecurityException
   {
-    if (handler == null)
-      throw new NullPointerException();
-
-    /* An application is allowed to control an anonymous logger
-     * without having the permission to control the logging
-     * infrastructure.
-     */
-    if (!anonymous)
-      LogManager.getLogManager().checkAccess();
-
-    if (!handlerList.contains(handler))
-    {
-      handlerList.add(handler);
-      handlers = getHandlers();
-    }
+    synchronized (lock)
+      {
+        if (handler == null)
+          throw new NullPointerException();
+
+        /*
+         * An application is allowed to control an anonymous logger without
+         * having the permission to control the logging infrastructure.
+         */
+        if (! anonymous)
+          LogManager.getLogManager().checkAccess();
+
+        if (! handlerList.contains(handler))
+          {
+            handlerList.add(handler);
+            handlers = getHandlers();
+          }
+      }
   }
 
-
   /**
-   * Removes a handler from the set of handlers that get notified
-   * when a log record is to be published.
-   *
+   * Removes a handler from the set of handlers that get notified when a log
+   * record is to be published.
+   * 
    * @param handler the handler to be removed.
-   *
-   * @throws SecurityException if this logger is not anonymous, a
-   *     security manager exists, and the caller is not granted the
-   *     permission to control the logging infrastructure by having
-   *     LoggingPermission("control").  Untrusted code can obtain an
-   *     anonymous logger through the static factory method {@link
-   *     #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
-   *
-   * @throws NullPointerException if <code>handler</code>
-   *     is <code>null</code>.
+   * @throws SecurityException if this logger is not anonymous, a security
+   *             manager exists, and the caller is not granted the permission to
+   *             control the logging infrastructure by having
+   *             LoggingPermission("control"). Untrusted code can obtain an
+   *             anonymous logger through the static factory method {@link
+   *             #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
+   * @throws NullPointerException if <code>handler</code> is <code>null</code>.
    */
-  public synchronized void removeHandler(Handler handler)
-    throws SecurityException
+  public void removeHandler(Handler handler) throws SecurityException
   {
-    /* An application is allowed to control an anonymous logger
-     * without having the permission to control the logging
-     * infrastructure.
-     */
-    if (!anonymous)
-      LogManager.getLogManager().checkAccess();
-
-    if (handler == null)
-      throw new NullPointerException();
-
-    handlerList.remove(handler);
-    handlers = getHandlers();
+    synchronized (lock)
+      {
+        /*
+         * An application is allowed to control an anonymous logger without
+         * having the permission to control the logging infrastructure.
+         */
+        if (! anonymous)
+          LogManager.getLogManager().checkAccess();
+
+        if (handler == null)
+          throw new NullPointerException();
+
+        handlerList.remove(handler);
+        handlers = getHandlers();
+      }
   }
 
-
   /**
-   * Returns the handlers currently registered for this Logger.
-   * When a log record has been deemed as being loggable,
-   * it will be passed to all registered handlers for
-   * publication.  In addition, if the logger uses parent handlers
-   * (see {@link #getUseParentHandlers() getUseParentHandlers}
-   * and {@link #setUseParentHandlers(boolean) setUseParentHandlers},
-   * the log record will be passed to the parent's handlers.
+   * Returns the handlers currently registered for this Logger. When a log
+   * record has been deemed as being loggable, it will be passed to all
+   * registered handlers for publication. In addition, if the logger uses parent
+   * handlers (see {@link #getUseParentHandlers() getUseParentHandlers} and
+   * {@link #setUseParentHandlers(boolean) setUseParentHandlers}, the log
+   * record will be passed to the parent's handlers.
    */
-  public synchronized Handler[] getHandlers()
+  public Handler[] getHandlers()
   {
-    /* We cannot return our internal handlers array
-     * because we do not have any guarantee that the
-     * caller would not change the array entries.
-     */
-    return (Handler[]) handlerList.toArray(new Handler[handlerList.size()]);
+    synchronized (lock)
+      {
+        /*
+         * We cannot return our internal handlers array because we do not have
+         * any guarantee that the caller would not change the array entries.
+         */
+        return (Handler[]) handlerList.toArray(new Handler[handlerList.size()]);
+      }
   }
 
-
   /**
-   * Returns whether or not this Logger forwards log records to
-   * handlers registered for its parent loggers.
-   *
-   * @return <code>false</code> if this Logger sends log records
-   *         merely to Handlers registered with itself;
-   *         <code>true</code> if this Logger sends log records
-   *         not only to Handlers registered with itself, but also
-   *         to those Handlers registered with parent loggers.
+   * Returns whether or not this Logger forwards log records to handlers
+   * registered for its parent loggers.
+   * 
+   * @return <code>false</code> if this Logger sends log records merely to
+   *         Handlers registered with itself; <code>true</code> if this Logger
+   *         sends log records not only to Handlers registered with itself, but
+   *         also to those Handlers registered with parent loggers.
    */
-  public synchronized boolean getUseParentHandlers()
+  public boolean getUseParentHandlers()
   {
-    return useParentHandlers;
+    synchronized (lock)
+      {
+        return useParentHandlers;
+      }
   }
 
-
   /**
-   * Sets whether or not this Logger forwards log records to
-   * handlers registered for its parent loggers.
-   *
-   * @param useParentHandlers <code>false</code> to let this
-   *         Logger send log records merely to Handlers registered
-   *         with itself; <code>true</code> to let this Logger
-   *         send log records not only to Handlers registered
-   *         with itself, but also to those Handlers registered with
-   *         parent loggers.
-   *
-   * @throws SecurityException if this logger is not anonymous, a
-   *     security manager exists, and the caller is not granted
-   *     the permission to control the logging infrastructure by
-   *     having LoggingPermission("control").  Untrusted code can
-   *     obtain an anonymous logger through the static factory method
-   *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
-   *
+   * Sets whether or not this Logger forwards log records to handlers registered
+   * for its parent loggers.
+   * 
+   * @param useParentHandlers <code>false</code> to let this Logger send log
+   *            records merely to Handlers registered with itself;
+   *            <code>true</code> to let this Logger send log records not only
+   *            to Handlers registered with itself, but also to those Handlers
+   *            registered with parent loggers.
+   * @throws SecurityException if this logger is not anonymous, a security
+   *             manager exists, and the caller is not granted the permission to
+   *             control the logging infrastructure by having
+   *             LoggingPermission("control"). Untrusted code can obtain an
+   *             anonymous logger through the static factory method
+   *             {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
    */
-  public synchronized void setUseParentHandlers(boolean useParentHandlers)
+  public void setUseParentHandlers(boolean useParentHandlers)
   {
-    /* An application is allowed to control an anonymous logger
-     * without having the permission to control the logging
-     * infrastructure.
-     */
-    if (!anonymous)
-      LogManager.getLogManager().checkAccess();
-
-    this.useParentHandlers = useParentHandlers;
+    synchronized (lock)
+      {
+        /*
+         * An application is allowed to control an anonymous logger without
+         * having the permission to control the logging infrastructure.
+         */
+        if (! anonymous)
+          LogManager.getLogManager().checkAccess();
+
+        this.useParentHandlers = useParentHandlers;
+      }
   }
 
-
   /**
-   * Returns the parent of this logger.  By default, the parent is
-   * assigned by the LogManager by inspecting the logger's name.
-   *
-   * @return the parent of this logger (as detemined by the LogManager
-   *     by inspecting logger names), the root logger if no other
-   *     logger has a name which is a prefix of this logger's name, or
-   *     <code>null</code> for the root logger.
+   * Returns the parent of this logger. By default, the parent is assigned by
+   * the LogManager by inspecting the logger's name.
+   * 
+   * @return the parent of this logger (as detemined by the LogManager by
+   *         inspecting logger names), the root logger if no other logger has a
+   *         name which is a prefix of this logger's name, or <code>null</code>
+   *         for the root logger.
    */
-  public synchronized Logger getParent()
+  public Logger getParent()
   {
-    return parent;
+    synchronized (lock)
+      {
+        return parent;
+      }
   }
 
-
   /**
-   * Sets the parent of this logger.  Usually, applications do not
-   * call this method directly.  Instead, the LogManager will ensure
-   * that the tree of loggers reflects the hierarchical logger
-   * namespace.  Basically, this method should not be public at all,
-   * but the GNU implementation follows the API specification.
-   *
-   * @throws NullPointerException if <code>parent</code> is
-   *     <code>null</code>.
-   *
-   * @throws SecurityException if this logger is not anonymous, a
-   *     security manager exists, and the caller is not granted
-   *     the permission to control the logging infrastructure by
-   *     having LoggingPermission("control").  Untrusted code can
-   *     obtain an anonymous logger through the static factory method
-   *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
+   * Sets the parent of this logger. Usually, applications do not call this
+   * method directly. Instead, the LogManager will ensure that the tree of
+   * loggers reflects the hierarchical logger namespace. Basically, this method
+   * should not be public at all, but the GNU implementation follows the API
+   * specification.
+   * 
+   * @throws NullPointerException if <code>parent</code> is <code>null</code>.
+   * @throws SecurityException if this logger is not anonymous, a security
+   *             manager exists, and the caller is not granted the permission to
+   *             control the logging infrastructure by having
+   *             LoggingPermission("control"). Untrusted code can obtain an
+   *             anonymous logger through the static factory method
+   *             {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
    */
-  public synchronized void setParent(Logger parent)
+  public void setParent(Logger parent)
   {
-    if (parent == null)
-      throw new NullPointerException();
+    synchronized (lock)
+      {
+        if (parent == null)
+          throw new NullPointerException();
 
-    if (this == root)
-        throw new IllegalArgumentException(
-          "the root logger can only have a null parent");
+        if (this == root)
+          throw new IllegalArgumentException(
+                                             "the root logger can only have a null parent");
 
-    /* An application is allowed to control an anonymous logger
-     * without having the permission to control the logging
-     * infrastructure.
-     */
-    if (!anonymous)
-      LogManager.getLogManager().checkAccess();
+        /*
+         * An application is allowed to control an anonymous logger without
+         * having the permission to control the logging infrastructure.
+         */
+        if (! anonymous)
+          LogManager.getLogManager().checkAccess();
 
-    this.parent = parent;
+        this.parent = parent;
+      }
   }
-  
+
   /**
-   * Gets the StackTraceElement of the first class that is not this class.
-   * That should be the initial caller of a logging method.
+   * Gets the StackTraceElement of the first class that is not this class. That
+   * should be the initial caller of a logging method.
+   * 
    * @return caller of the initial logging method or null if unknown.
    */
   private StackTraceElement getCallerStackFrame()
@@ -1195,18 +1163,18 @@ public class Logger
     int index = 0;
 
     // skip to stackentries until this class
-    while(index < stackTrace.length
-         && !stackTrace[index].getClassName().equals(getClass().getName()))
+    while (index < stackTrace.length
+           && ! stackTrace[index].getClassName().equals(getClass().getName()))
       index++;
 
     // skip the stackentries of this class
-    while(index < stackTrace.length
-         && stackTrace[index].getClassName().equals(getClass().getName()))
+    while (index < stackTrace.length
+           && stackTrace[index].getClassName().equals(getClass().getName()))
       index++;
 
     return index < stackTrace.length ? stackTrace[index] : null;
   }
-  
+
   /**
    * Reset and close handlers attached to this logger. This function is package
    * private because it must only be available to the LogManager.