You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by rd...@apache.org on 2004/12/15 11:35:19 UTC
cvs commit: jakarta-commons/logging/optional/src/java/org/apache/commons/logging/impl WeakHashtable.java
rdonkin 2004/12/15 02:35:19
Modified: logging/optional/src/java/org/apache/commons/logging/impl
WeakHashtable.java
Log:
Improved housekeeping and simplified code for WeakHashTable. Issue#31286. Submitted by Brian Stansberry.
Revision Changes Path
1.6 +62 -99 jakarta-commons/logging/optional/src/java/org/apache/commons/logging/impl/WeakHashtable.java
Index: WeakHashtable.java
===================================================================
RCS file: /home/cvs/jakarta-commons/logging/optional/src/java/org/apache/commons/logging/impl/WeakHashtable.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- WeakHashtable.java 25 Nov 2004 20:09:53 -0000 1.5
+++ WeakHashtable.java 15 Dec 2004 10:35:19 -0000 1.6
@@ -68,36 +68,29 @@
*/
public final class WeakHashtable extends Hashtable {
- /** Empty array of <code>Entry</code>'s */
- private static final Entry[] EMPTY_ENTRY_ARRAY = {};
/**
- * The maximum number of times put() can be called before
- * the map will purged of cleared entries.
+ * The maximum number of times put() or remove() can be called before
+ * the map will be purged of all cleared entries.
*/
- public static final int MAX_PUTS_BEFORE_PURGE = 100;
-
+ private static final int MAX_CHANGES_BEFORE_PURGE = 100;
+
+ /**
+ * The maximum number of times put() or remove() can be called before
+ * the map will be purged of one cleared entry.
+ */
+ private static final int PARTIAL_PURGE_COUNT = 10;
+
/* ReferenceQueue we check for gc'd keys */
private ReferenceQueue queue = new ReferenceQueue();
/* Counter used to control how often we purge gc'd entries */
- private int putCount = 0;
+ private int changeCount = 0;
/**
* Constructs a WeakHashtable with the Hashtable default
* capacity and load factor.
*/
public WeakHashtable() {}
-
- /**
- *@see Hashtable
- */
- public boolean contains(Object value) {
- // purge should not be required
- if (value instanceof Referenced) {
- return super.contains(value);
- }
- Referenced referenced = new Referenced(value);
- return super.contains(referenced);
- }
+
/**
*@see Hashtable
@@ -111,30 +104,9 @@
/**
*@see Hashtable
*/
- public boolean containsValue(Object value) {
- // purge should not be required
- if (value instanceof Referenced) {
- return super.contains(value);
- }
- Referenced referenced = new Referenced(value);
- return super.containsValue(referenced);
- }
-
- /**
- *@see Hashtable
- */
public Enumeration elements() {
purge();
- final Enumeration enum = super.elements();
- return new Enumeration() {
- public boolean hasMoreElements() {
- return enum.hasMoreElements();
- }
- public Object nextElement() {
- Referenced nextReference = (Referenced) enum.nextElement();
- return nextReference.getValue();
- }
- };
+ return super.elements();
}
/**
@@ -148,8 +120,7 @@
Map.Entry entry = (Map.Entry) it.next();
Referenced referencedKey = (Referenced) entry.getKey();
Object key = referencedKey.getValue();
- Referenced referencedValue = (Referenced) entry.getValue();
- Object value = referencedValue.getValue();
+ Object value = entry.getValue();
if (key != null) {
Entry dereferencedEntry = new Entry(key, value);
unreferencedEntries.add(dereferencedEntry);
@@ -163,13 +134,8 @@
*/
public Object get(Object key) {
// for performance reasons, no purge
- Object result = null;
Referenced referenceKey = new Referenced(key);
- Referenced referencedValue = (Referenced) super.get(referenceKey);
- if (referencedValue != null) {
- result = referencedValue.getValue();
- }
- return result;
+ return super.get(referenceKey);
}
/**
@@ -177,13 +143,13 @@
*/
public Enumeration keys() {
purge();
- final Enumeration enum = super.keys();
+ final Enumeration enumer = super.keys();
return new Enumeration() {
public boolean hasMoreElements() {
- return enum.hasMoreElements();
+ return enumer.hasMoreElements();
}
public Object nextElement() {
- Referenced nextReference = (Referenced) enum.nextElement();
+ Referenced nextReference = (Referenced) enumer.nextElement();
return nextReference.getValue();
}
};
@@ -220,19 +186,19 @@
}
// for performance reasons, only purge every
- // MAX_PUTS_BEFORE_PURGE times
- if (putCount++ > MAX_PUTS_BEFORE_PURGE) {
+ // MAX_CHANGES_BEFORE_PURGE times
+ if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) {
purge();
- putCount = 0;
+ changeCount = 0;
}
- Object result = null;
- Referenced keyRef = new Referenced(key, value, queue);
- Referenced valueRef = new Referenced(value);
- Referenced lastValue = (Referenced) super.put(keyRef, valueRef);
- if (lastValue != null) {
- result = lastValue.getValue();
+ // do a partial purge more often
+ else if ((changeCount % PARTIAL_PURGE_COUNT) == 0) {
+ purgeOne();
}
- return result;
+
+ Object result = null;
+ Referenced keyRef = new Referenced(key, queue);
+ return super.put(keyRef, value);
}
/**
@@ -253,22 +219,23 @@
*/
public Collection values() {
purge();
- Collection referencedValues = super.values();
- ArrayList unreferencedValues = new ArrayList();
- for (Iterator it = referencedValues.iterator(); it.hasNext();) {
- Referenced reference = (Referenced) it.next();
- Object value = reference.getValue();
- if (value != null) {
- unreferencedValues.add(value);
- }
- }
- return unreferencedValues;
+ return super.values();
}
/**
*@see Hashtable
*/
public Object remove(Object key) {
+ // for performance reasons, only purge every
+ // MAX_CHANGES_BEFORE_PURGE times
+ if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) {
+ purge();
+ changeCount = 0;
+ }
+ // do a partial purge more often
+ else if ((changeCount % PARTIAL_PURGE_COUNT) == 0) {
+ purgeOne();
+ }
return super.remove(new Referenced(key));
}
@@ -309,10 +276,26 @@
* Purges all entries whose wrapped keys
* have been garbage collected.
*/
- private synchronized void purge() {
- WeakKey key;
- while ( (key = (WeakKey) queue.poll()) != null) {
- super.remove(key.getReferenced());
+ private void purge() {
+ synchronized (queue) {
+ WeakKey key;
+ while ((key = (WeakKey) queue.poll()) != null) {
+ super.remove(key.getReferenced());
+ }
+ }
+ }
+
+ /**
+ * Purges one entry whose wrapped key
+ * has been garbage collected.
+ */
+ private void purgeOne() {
+
+ synchronized (queue) {
+ WeakKey key = (WeakKey) queue.poll();
+ if (key != null) {
+ super.remove(key.getReferenced());
+ }
}
}
@@ -383,8 +366,8 @@
*
* @throws NullPointerException if key is <code>null</code>
*/
- private Referenced(Object key, Object value, ReferenceQueue queue) {
- reference = new WeakKey(key, value, queue, this);
+ private Referenced(Object key, ReferenceQueue queue) {
+ reference = new WeakKey(key, queue, this);
// Calc a permanent hashCode so calls to Hashtable.remove()
// work if the WeakReference has been cleared
hashCode = key.hashCode();
@@ -437,38 +420,18 @@
* the Referenced object holding it.
*/
private final static class WeakKey extends WeakReference {
-
- private final Object hardValue;
+
private final Referenced referenced;
private WeakKey(Object key,
- Object value,
ReferenceQueue queue,
Referenced referenced) {
super(key, queue);
- hardValue = value;
this.referenced = referenced;
}
private Referenced getReferenced() {
return referenced;
}
-
- /* Drop our hard reference to value if we've been cleared
- * by the gc.
- *
- * Testing shows that with key objects like ClassLoader
- * that don't override hashCode(), get() is never
- * called once the key is in a Hashtable.
- * So, this method override is commented out.
- */
- //public Object get() {
- // Object result = super.get();
- // if (result == null) {
- // // We've been cleared, so drop our hard reference to value
- // hardValue = null;
- // }
- // return result;
- //}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org