Class WeakHashtable
- java.lang.Object
-
- java.util.Dictionary<K,V>
-
- java.util.Hashtable
-
- org.apache.commons.logging.impl.WeakHashtable
-
- All Implemented Interfaces:
java.io.Serializable
,java.lang.Cloneable
,java.util.Map
public final class WeakHashtable extends java.util.Hashtable
Implementation ofHashtable
that usesWeakReference
's to hold its keys thus allowing them to be reclaimed by the garbage collector. The associated values are retained using strong references.This class follows the semantics of
Hashtable
as closely as possible. It therefore does not accept null values or keys.Note: This is not intended to be a general purpose hash table replacement. This implementation is also tuned towards a particular purpose: for use as a replacement for
Hashtable
inLogFactory
. This application requires good liveliness forget
andput
. Various tradeoffs have been made with this in mind.Usage: typical use case is as a drop-in replacement for the
Hashtable
used inLogFactory
for J2EE environments running 1.3+ JVMs. Use of this class in most cases (see below) will allow classloaders to be collected by the garbage collector without the need to callLogFactory.release(ClassLoader)
.org.apache.commons.logging.LogFactory
checks whether this class can be supported by the current JVM, and if so then uses it to store references to theLogFactory
implementation it loads (rather than using a standard Hashtable instance). Having this class used instead ofHashtable
solves certain issues related to dynamic reloading of applications in J2EE-style environments. However this class requires java 1.3 or later (due to its use ofjava.lang.ref.WeakReference
and associates). And by the way, this extendsHashtable
rather thanHashMap
for backwards compatibility reasons. See the documentation for methodLogFactory.createFactoryStore
for more details.The reason all this is necessary is due to a issue which arises during hot deploy in a J2EE-like containers. Each component running in the container owns one or more classloaders; when the component loads a LogFactory instance via the component classloader a reference to it gets stored in the static LogFactory.factories member, keyed by the component's classloader so different components don't stomp on each other. When the component is later unloaded, the container sets the component's classloader to null with the intent that all the component's classes get garbage-collected. However there's still a reference to the component's classloader from a key in the "global"
LogFactory
's factories member! IfLogFactory.release()
is called whenever component is unloaded, the classloaders will be correctly garbage collected; this should be done by any container that bundles commons-logging by default. However, holding the classloader references weakly ensures that the classloader will be garbage collected without the container performing this step.Limitations: There is still one (unusual) scenario in which a component will not be correctly unloaded without an explicit release. Though weak references are used for its keys, it is necessary to use strong references for its values.
If the abstract class
LogFactory
is loaded by the container classloader but a subclass ofLogFactory
[LogFactory1] is loaded by the component's classloader and an instance stored in the static map associated with the base LogFactory class, then there is a strong reference from the LogFactory class to the LogFactory1 instance (as normal) and a strong reference from the LogFactory1 instance to the component classloader viagetClass().getClassLoader()
. This chain of references will prevent collection of the child classloader.Such a situation occurs when the commons-logging.jar is loaded by a parent classloader (e.g. a server level classloader in a servlet container) and a custom
LogFactory
implementation is loaded by a child classloader (e.g. a web app classloader).To avoid this scenario, ensure that any custom LogFactory subclass is loaded by the same classloader as the base
LogFactory
. Creating custom LogFactory subclasses is, however, rare. The standard LogFactoryImpl class should be sufficient for most or all users.- Since:
- 1.1
- Version:
- $Id: WeakHashtable.java 1435077 2013-01-18 10:51:35Z tn $
- See Also:
- Serialized Form
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description private static class
WeakHashtable.Entry
Entry implementationprivate static class
WeakHashtable.Referenced
Wrapper giving correct symantics for equals and hashcodeprivate static class
WeakHashtable.WeakKey
WeakReference subclass that holds a hard reference to an associatedvalue
and also makes accessible the Referenced object holding it.
-
Field Summary
Fields Modifier and Type Field Description private int
changeCount
private static int
MAX_CHANGES_BEFORE_PURGE
The maximum number of times put() or remove() can be called before the map will be purged of all cleared entries.private static int
PARTIAL_PURGE_COUNT
The maximum number of times put() or remove() can be called before the map will be purged of one cleared entry.private java.lang.ref.ReferenceQueue
queue
private static long
serialVersionUID
Serializable version identifier.
-
Constructor Summary
Constructors Constructor Description WeakHashtable()
Constructs a WeakHashtable with the Hashtable default capacity and load factor.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description boolean
containsKey(java.lang.Object key)
java.util.Enumeration
elements()
java.util.Set
entrySet()
java.lang.Object
get(java.lang.Object key)
boolean
isEmpty()
java.util.Enumeration
keys()
java.util.Set
keySet()
private void
purge()
Purges all entries whose wrapped keys have been garbage collected.private void
purgeOne()
Purges one entry whose wrapped key has been garbage collected.java.lang.Object
put(java.lang.Object key, java.lang.Object value)
void
putAll(java.util.Map t)
protected void
rehash()
java.lang.Object
remove(java.lang.Object key)
int
size()
java.lang.String
toString()
java.util.Collection
values()
-
-
-
Field Detail
-
serialVersionUID
private static final long serialVersionUID
Serializable version identifier.- See Also:
- Constant Field Values
-
MAX_CHANGES_BEFORE_PURGE
private static final int MAX_CHANGES_BEFORE_PURGE
The maximum number of times put() or remove() can be called before the map will be purged of all cleared entries.- See Also:
- Constant Field Values
-
PARTIAL_PURGE_COUNT
private static final int PARTIAL_PURGE_COUNT
The maximum number of times put() or remove() can be called before the map will be purged of one cleared entry.- See Also:
- Constant Field Values
-
queue
private final java.lang.ref.ReferenceQueue queue
-
changeCount
private int changeCount
-
-
Method Detail
-
containsKey
public boolean containsKey(java.lang.Object key)
- Specified by:
containsKey
in interfacejava.util.Map
- Overrides:
containsKey
in classjava.util.Hashtable
- See Also:
Hashtable
-
elements
public java.util.Enumeration elements()
- Overrides:
elements
in classjava.util.Hashtable
- See Also:
Hashtable
-
entrySet
public java.util.Set entrySet()
- Specified by:
entrySet
in interfacejava.util.Map
- Overrides:
entrySet
in classjava.util.Hashtable
- See Also:
Hashtable
-
get
public java.lang.Object get(java.lang.Object key)
- Specified by:
get
in interfacejava.util.Map
- Overrides:
get
in classjava.util.Hashtable
- See Also:
Hashtable
-
keys
public java.util.Enumeration keys()
- Overrides:
keys
in classjava.util.Hashtable
- See Also:
Hashtable
-
keySet
public java.util.Set keySet()
- Specified by:
keySet
in interfacejava.util.Map
- Overrides:
keySet
in classjava.util.Hashtable
- See Also:
Hashtable
-
put
public java.lang.Object put(java.lang.Object key, java.lang.Object value)
- Specified by:
put
in interfacejava.util.Map
- Overrides:
put
in classjava.util.Hashtable
- See Also:
Hashtable
-
putAll
public void putAll(java.util.Map t)
- Specified by:
putAll
in interfacejava.util.Map
- Overrides:
putAll
in classjava.util.Hashtable
- See Also:
Hashtable
-
values
public java.util.Collection values()
- Specified by:
values
in interfacejava.util.Map
- Overrides:
values
in classjava.util.Hashtable
- See Also:
Hashtable
-
remove
public java.lang.Object remove(java.lang.Object key)
- Specified by:
remove
in interfacejava.util.Map
- Overrides:
remove
in classjava.util.Hashtable
- See Also:
Hashtable
-
isEmpty
public boolean isEmpty()
- Specified by:
isEmpty
in interfacejava.util.Map
- Overrides:
isEmpty
in classjava.util.Hashtable
- See Also:
Hashtable
-
size
public int size()
- Specified by:
size
in interfacejava.util.Map
- Overrides:
size
in classjava.util.Hashtable
- See Also:
Hashtable
-
toString
public java.lang.String toString()
- Overrides:
toString
in classjava.util.Hashtable
- See Also:
Hashtable
-
rehash
protected void rehash()
- Overrides:
rehash
in classjava.util.Hashtable
- See Also:
Hashtable
-
purge
private void purge()
Purges all entries whose wrapped keys have been garbage collected.
-
purgeOne
private void purgeOne()
Purges one entry whose wrapped key has been garbage collected.
-
-