001: /*
002: * @(#)WeakCache.java 1.14 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package sun.misc;
029:
030: /**
031: * This is a hash table that uses a sun.misc.Ref to store its values.
032: * With each operation, this hash table will put a little
033: * bit of work into checking for ref's that have been nulled out by the
034: * GC. When it detects that this has happened, it removes the corresponding
035: * key from the hashtable. This prevents the hashtable from leaking keys.
036: */
037:
038: public class WeakCache extends java.util.Hashtable {
039: private java.util.Vector keyVector;
040: private int cleanupIndex = 0;
041:
042: //
043: // We use a weak ref to store the value. sun.misc.Ref is abstract,
044: // and we need to override reconstitute. We don't want it to actually
045: // do anything, though -- if a value disappears from the cache, it just
046: // goes away.
047: //
048: private static class Value extends Ref {
049: public Value(Object t) {
050: super ();
051: setThing(t);
052: }
053:
054: public Object reconstitute() {
055: return null;
056: }
057: }
058:
059: public WeakCache() {
060: super ();
061: keyVector = new java.util.Vector();
062: }
063:
064: public WeakCache(int initialCapacity) {
065: super (initialCapacity);
066: keyVector = new java.util.Vector(initialCapacity);
067: }
068:
069: public synchronized Object get(Object key) {
070: Object returnVal = super .get(key);
071: doSomeCleanup(1);
072: if (returnVal != null) {
073: return ((Value) returnVal).get();
074: } else {
075: return null;
076: }
077: }
078:
079: public synchronized Object put(Object key, Object value) {
080: if (!(value instanceof Value)) {
081: value = new Value(value);
082: }
083: Object returnVal = super .put(key, value);
084: if (returnVal == null) {
085: keyVector.addElement(key);
086: }
087: doSomeCleanup(2);
088: return returnVal;
089: }
090:
091: public synchronized Object remove(Object key) {
092: Object returnVal = super .remove(key);
093: keyVector.removeElement(key);
094: doSomeCleanup(2);
095: return returnVal;
096: }
097:
098: protected synchronized void doSomeCleanup(int amountOfCleanup) {
099: if (keyVector.size() == 0)
100: return;
101: for (; amountOfCleanup != 0; amountOfCleanup--) {
102: // In the case where the cleanupIndex is at the end of the
103: // Vector and then an element is removed, the cleanupIndex
104: // will be out of bounds. So, before the cleanupIndex is
105: // used, make sure it is in bounds.
106: if (cleanupIndex >= keyVector.size()) {
107: cleanupIndex = 0;
108: break;
109: }
110: Object key = keyVector.elementAt(cleanupIndex);
111: // If the value of this key in the hashtable has been
112: // garbage collected, remove the key.
113: Object v = super .get(key);
114: if (v instanceof sun.misc.Ref
115: && ((sun.misc.Ref) v).check() == null) {
116: super .remove(key);
117: keyVector.removeElement(key);
118: if (keyVector.size() == 0) {
119: cleanupIndex = 0;
120: return;
121: }
122: } else {
123: // Otherwise, move the pointer to the next
124: // element in the vector
125: cleanupIndex++;
126: }
127: // Finally, modulate the index to loop back around to
128: // the start of the vector once you hit the end.
129: cleanupIndex = cleanupIndex % keyVector.size();
130: }
131: }
132: }
|