6797480: Remove synchronization bottleneck in logger
authormartin
Tue, 27 Jan 2009 15:04:30 -0800
changeset 1933 1210d93b6ee7
parent 1932 d3506bce7d27
child 1934 94b646161f34
6797480: Remove synchronization bottleneck in logger Reviewed-by: swamyv Contributed-by: jeremymanson@google.com
jdk/src/share/classes/java/util/logging/Logger.java
--- a/jdk/src/share/classes/java/util/logging/Logger.java	Tue Jan 27 11:36:28 2009 +0100
+++ b/jdk/src/share/classes/java/util/logging/Logger.java	Tue Jan 27 15:04:30 2009 -0800
@@ -27,6 +27,7 @@
 package java.util.logging;
 
 import java.util.*;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.security.*;
 import java.lang.ref.WeakReference;
 
@@ -165,10 +166,11 @@
     private static final int offValue = Level.OFF.intValue();
     private LogManager manager;
     private String name;
-    private ArrayList<Handler> handlers;
+    private final CopyOnWriteArrayList<Handler> handlers =
+        new CopyOnWriteArrayList<Handler>();
     private String resourceBundleName;
-    private boolean useParentHandlers = true;
-    private Filter filter;
+    private volatile boolean useParentHandlers = true;
+    private volatile Filter filter;
     private boolean anonymous;
 
     private ResourceBundle catalog;     // Cached resource bundle
@@ -180,9 +182,9 @@
     private static Object treeLock = new Object();
     // We keep weak references from parents to children, but strong
     // references from children to parents.
-    private Logger parent;    // our nearest parent.
+    private volatile Logger parent;    // our nearest parent.
     private ArrayList<WeakReference<Logger>> kids;   // WeakReferences to loggers that have us as parent
-    private Level levelObject;
+    private volatile Level levelObject;
     private volatile int levelValue;  // current effective level value
 
     /**
@@ -438,7 +440,7 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have LoggingPermission("control").
      */
-    public synchronized void setFilter(Filter newFilter) throws SecurityException {
+    public void setFilter(Filter newFilter) throws SecurityException {
         checkAccess();
         filter = newFilter;
     }
@@ -448,7 +450,7 @@
      *
      * @return  a filter object (may be null)
      */
-    public synchronized Filter getFilter() {
+    public Filter getFilter() {
         return filter;
     }
 
@@ -465,10 +467,9 @@
         if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
             return;
         }
-        synchronized (this) {
-            if (filter != null && !filter.isLoggable(record)) {
-                return;
-            }
+        Filter theFilter = filter;
+        if (theFilter != null && !theFilter.isLoggable(record)) {
+            return;
         }
 
         // Post the LogRecord to all our Handlers, and then to
@@ -476,12 +477,8 @@
 
         Logger logger = this;
         while (logger != null) {
-            Handler targets[] = logger.getHandlers();
-
-            if (targets != null) {
-                for (int i = 0; i < targets.length; i++) {
-                    targets[i].publish(record);
-                }
+            for (Handler handler : logger.handlers) {
+                handler.publish(record);
             }
 
             if (!logger.getUseParentHandlers()) {
@@ -1182,13 +1179,10 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have LoggingPermission("control").
      */
-    public synchronized void addHandler(Handler handler) throws SecurityException {
+    public void addHandler(Handler handler) throws SecurityException {
         // Check for null handler
         handler.getClass();
         checkAccess();
-        if (handlers == null) {
-            handlers = new ArrayList<Handler>();
-        }
         handlers.add(handler);
     }
 
@@ -1201,14 +1195,11 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have LoggingPermission("control").
      */
-    public synchronized void removeHandler(Handler handler) throws SecurityException {
+    public void removeHandler(Handler handler) throws SecurityException {
         checkAccess();
         if (handler == null) {
             return;
         }
-        if (handlers == null) {
-            return;
-        }
         handlers.remove(handler);
     }
 
@@ -1217,11 +1208,8 @@
      * <p>
      * @return  an array of all registered Handlers
      */
-    public synchronized Handler[] getHandlers() {
-        if (handlers == null) {
-            return emptyHandlers;
-        }
-        return handlers.toArray(new Handler[handlers.size()]);
+    public Handler[] getHandlers() {
+        return handlers.toArray(emptyHandlers);
     }
 
     /**
@@ -1235,7 +1223,7 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have LoggingPermission("control").
      */
-    public synchronized void setUseParentHandlers(boolean useParentHandlers) {
+    public void setUseParentHandlers(boolean useParentHandlers) {
         checkAccess();
         this.useParentHandlers = useParentHandlers;
     }
@@ -1246,7 +1234,7 @@
      *
      * @return  true if output is to be sent to the logger's parent
      */
-    public synchronized boolean getUseParentHandlers() {
+    public boolean getUseParentHandlers() {
         return useParentHandlers;
     }
 
@@ -1354,9 +1342,12 @@
      * @return nearest existing parent Logger
      */
     public Logger getParent() {
-        synchronized (treeLock) {
-            return parent;
-        }
+        // Note: this used to be synchronized on treeLock.  However, this only
+        // provided memory semantics, as there was no guarantee that the caller
+        // would synchronize on treeLock (in fact, there is no way for external
+        // callers to so synchronize).  Therefore, we have made parent volatile
+        // instead.
+        return parent;
     }
 
     /**