[PATCH 2/2] Class loader local storage

David M. Lloyd david.lloyd at redhat.com
Thu Feb 26 16:07:00 UTC 2009


This second patch adds a ClassLoaderLocal mechanism.  The cost is one 
reference per class loader, plus one WeakHashMap for every class class 
loader which has local information associated with it.  The map has one key 
for every ClassLoaderLocal which is currently storing data on this 
ClassLoaderLocal.

- DML

--
diff -r dde3fe2e8164 src/share/classes/java/lang/ClassLoader.java
--- a/src/share/classes/java/lang/ClassLoader.java	Wed Feb 25 14:32:01 2009 
+0000
+++ b/src/share/classes/java/lang/ClassLoader.java	Thu Feb 26 09:53:12 2009 
-0600
@@ -48,6 +48,7 @@
  import java.util.Stack;
  import java.util.Map;
  import java.util.Vector;
+import java.util.WeakHashMap;
  import sun.misc.ClassFileTransformer;
  import sun.misc.CompoundEnumeration;
  import sun.misc.Resource;
@@ -2012,6 +2013,17 @@

      // Retrieves the assertion directives from the VM.
      private static native AssertionStatusDirectives retrieveDirectives();
+
+    private Map<Object, Object> classLoaderLocalMap;
+
+    Map<Object, Object> getClassLoaderLocalMap() {
+        final Map<Object, Object> classLoaderLocalMap = 
this.classLoaderLocalMap;
+        if (classLoaderLocalMap == null) {
+            return (this.classLoaderLocalMap = new WeakHashMap<Object, 
Object>());
+        } else {
+            return classLoaderLocalMap;
+        }
+    }
  }


diff -r dde3fe2e8164 src/share/classes/java/lang/ClassLoaderLocal.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/ClassLoaderLocal.java	Thu Feb 26 09:53:12 
2009 -0600
@@ -0,0 +1,211 @@
+/*
+ * Copyright 1994-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package java.lang;
+
+import java.util.Map;
+
+/**
+ * This class provides class loader local variables.  Data stored in a class
+ * loader local variable is strongly referenced by the class loader it is
+ * associated with.
+ *
+ * @author David M. Lloyd
+ * @param <T> the type of the value of this class loader local variable
+ * @since 1.7
+ */
+public final class ClassLoaderLocal<T> {
+    private volatile Object key = new Object();
+
+    /**
+     * Construct a new instance.  A new instance will contain no mappings.
+     */
+    public ClassLoaderLocal() {
+    }
+
+    /**
+     * Determine whether the given class has a mapping for this  variable 
(even
+     * if it is {@code null}).
+     *
+     * @param classLoader the class loader to check
+     *
+     * @return {@code true} if the given class loader contains a value for 
this
+     *         variable
+     */
+    public boolean hasValue(ClassLoader classLoader) {
+        synchronized (classLoader) {
+            return classLoader.getClassLoaderLocalMap().containsKey(key);
+        }
+    }
+
+    /**
+     * Get the value associated with the given class loader for this variable.
+     *
+     * @return the value associated with the given class, or {@code null} if
+     *         there is no mapping (a {@code null} return could also indicate
+     *         that a {@code null} value is stored in this variable)
+     */
+    public T get(ClassLoader classLoader) {
+        synchronized (classLoader) {
+            return (T) classLoader.getClassLoaderLocalMap().get(key);
+        }
+    }
+
+    /**
+     * Associate a new value with the given class loader for this variable.
+     *
+     * @param classLoader the class loader to update
+     * @param value the value to associate
+     *
+     * @return the previous value associated with this variable, or {@code 
null}
+     *         if there was no mapping (a {@code null} return could also
+     *         indicate that a {@code null} value was stored in this variable)
+     */
+    public T put(ClassLoader classLoader, T value) {
+        synchronized (classLoader) {
+            return (T) classLoader.getClassLoaderLocalMap().put(key, value);
+        }
+    }
+
+    /**
+     * Associate a value with the given class loader for this variable if 
there
+     * was previously no mapping.
+     *
+     * @param classLoader the class loader to update
+     * @param value the value to associate
+     *
+     * @return the previous value associated with this variable, or {@code 
null}
+     *         if there was no mapping (a {@code null} return could also
+     *         indicate that a {@code null} value was stored in this variable)
+     */
+    public T putIfAbsent(ClassLoader classLoader, T value) {
+        synchronized (classLoader) {
+            final Object key = this.key;
+            final Map<Object, Object> cllMap =
+                    classLoader.getClassLoaderLocalMap();
+            if (cllMap.containsKey(key)) {
+                return (T) cllMap.get(key);
+            } else {
+                cllMap.put(key, value);
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Get and remove the value of this variable.  After this method returns,
+     * there will be no value stored in this variable for the given class 
loader
+     * (calling {@code hasValue(classLoader)} for this class loader and 
variable
+     * will return {@code false}).
+     *
+     * @param classLoader the class loader to update
+     *
+     * @return the previous value associated with this variable, or {@code 
null}
+     *         if there was no mapping (a {@code null} return could also
+     *         indicate that a {@code null} value was stored in this variable)
+     */
+    public T remove(ClassLoader classLoader) {
+        synchronized (classLoader) {
+            return (T) classLoader.getClassLoaderLocalMap().remove(key);
+        }
+    }
+
+    /**
+     * Remove the entry for this variable only if it is currently set to a 
given
+     * value.
+     *
+     * @param classLoader the class loader to update
+     * @param oldValue the value expected to be associated with the variable
+     *
+     * @return {@code true} if the value was removed
+     */
+    public boolean remove(ClassLoader classLoader, T oldValue) {
+        synchronized (classLoader) {
+            final Map<Object, Object> cllMap =
+                    classLoader.getClassLoaderLocalMap();
+            final Object key = this.key;
+            if (cllMap.containsKey(key) && cllMap.get(key).equals(oldValue)) {
+                cllMap.remove(key);
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Replace the entry for this variable, returning the old value.
+     *
+     * @param classLoader the class loader to update
+     * @param newValue the value to associate with this variable
+     *
+     * @return the previous value associated with this variable, or {@code 
null}
+     *         if there was no mapping (a {@code null} return could also
+     *         indicate that a {@code null} value was stored in this variable)
+     */
+    public T replace(ClassLoader classLoader, T newValue) {
+        synchronized (classLoader) {
+            final Map<Object, Object> cllMap =
+                    classLoader.getClassLoaderLocalMap();
+            final Object key = this.key;
+            if (cllMap.containsKey(key)) {
+                return (T) cllMap.put(key, newValue);
+            } else {
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Replace the entry for this variable, if it was previously set to a 
given
+     * value.
+     *
+     * @param classLoader the class loader to update
+     * @param oldValue the value expected to be associated with the variable
+     * @param newValue the value to associate with this variable
+     *
+     * @return {@code true} if the value was replaced
+     */
+    public boolean replace(ClassLoader classLoader, T oldValue, T newValue) {
+        synchronized (classLoader) {
+            final Map<Object, Object> cllMap =
+                    classLoader.getClassLoaderLocalMap();
+            final Object key = this.key;
+            if (cllMap.containsKey(key) && cllMap.get(key).equals(oldValue)) {
+                cllMap.put(key, newValue);
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Cause all existing mappings to be cleared.  Once this method is called,
+     * prior values are no longer retrievable.
+     */
+    public void clear() {
+        key = new Object();
+    }
+}
\ No newline at end of file




More information about the core-libs-dev mailing list