001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2001, Institut de Recherche pour le D�veloppement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.util;
018:
019: // J2SE dependencies
020: import java.lang.ref.Reference;
021: import java.lang.ref.ReferenceQueue;
022:
023: // Geotools dependencies
024: import org.geotools.util.logging.Logging;
025:
026: /**
027: * A thread invoking {@link Reference#clear} on each enqueded reference.
028: * This is usefull only if {@code Reference} subclasses has overridden
029: * their {@code clear()} method in order to perform some cleaning.
030: * This thread is used by {@link WeakHashSet} and {@link WeakValueHashMap},
031: * which remove their entry from the collection when {@link Reference#clear}
032: * is invoked.
033: *
034: * @since 2.0
035: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/util/WeakCollectionCleaner.java $
036: * @version $Id: WeakCollectionCleaner.java 27862 2007-11-12 19:51:19Z desruisseaux $
037: * @author Martin Desruisseaux
038: */
039: final class WeakCollectionCleaner extends Thread {
040: /**
041: * The name of the logger to use.
042: */
043: private static final String LOGGER = "org.geotools.util";
044:
045: /**
046: * The default thread.
047: */
048: public static final WeakCollectionCleaner DEFAULT = new WeakCollectionCleaner();
049:
050: /**
051: * List of reference collected by the garbage collector.
052: * Those elements must be removed from {@link #table}.
053: */
054: final ReferenceQueue referenceQueue = new ReferenceQueue();
055:
056: /**
057: * Constructs and starts a new thread as a daemon. This thread will be sleeping
058: * most of the time. It will run only some few nanoseconds each time a new
059: * {@link WeakReference} is enqueded.
060: */
061: private WeakCollectionCleaner() {
062: super ("WeakCollectionCleaner");
063: setPriority(MAX_PRIORITY - 2);
064: setDaemon(true);
065: start();
066: }
067:
068: /**
069: * Loop to be run during the virtual machine lifetime.
070: */
071: public void run() {
072: // The reference queue should never be null. However some strange cases (maybe caused
073: // by an anormal JVM state) have been reported on the mailing list. In such case, stop
074: // the daemon instead of writting 50 Mb of log messages.
075: while (referenceQueue != null) {
076: try {
077: // Block until a reference is enqueded.
078: final Reference ref = referenceQueue.remove();
079: if (ref == null) {
080: /*
081: * Should never happen according Sun's Javadoc ("Removes the next reference
082: * object in this queue, blocking until one becomes available."). However a
083: * null reference seems to be returned during JVM shutdown on Linux. Wait a
084: * few seconds in order to give the JVM a chance to kill this daemon thread
085: * before the logging at the sever level, and stop the loop. We do not try
086: * to resume the loop since something is apparently going wrong and we want
087: * the user to be notified. See GEOT-1138.
088: */
089: sleep(15 * 1000L);
090: break;
091: }
092: ref.clear();
093: // Note: To be usefull, the clear() method must have been overridden in Reference
094: // subclasses. This is what WeakHashSet.Entry and WeakHashMap.Entry do.
095: } catch (InterruptedException exception) {
096: // Somebody doesn't want to lets us sleep... Go back to work.
097: } catch (Exception exception) {
098: Logging.unexpectedException(LOGGER,
099: WeakCollectionCleaner.class, "remove",
100: exception);
101: } catch (AssertionError exception) {
102: Logging.unexpectedException(LOGGER,
103: WeakCollectionCleaner.class, "remove",
104: exception);
105: // Do not kill the thread on assertion failure, in order to
106: // keep the same behaviour as if assertions were turned off.
107: }
108: }
109: Logging.getLogger(LOGGER).severe("Daemon stopped."); // Should never happen.
110: }
111: }
|