Hi Roland,

Below are some comments on your questions.

1. a connection is allocated. Then the TSCCM will not be
   GCed, because an entry in REFERENCE_TO_CONNECTION_SOURCE
   prevents it. The entry references the ConnectionPool,
   which is a non-static nested class of the TSCCM, and
   therefore implicitly references the TSCCM.

REFERENCE_TO_CONNECTION_SOURCE will only have a reference to a
ConnectionPool if a connection is checked out and hasn't been GCed (is
this what you mean by allocated?).  In the case when a connnection is
checked out and still active there will be many direct references to
the pool and connection manager so this shouldn't be an issue.

In the case when a connection is checked out, lost, and then GCed the
reference from the REFERENCE_TO_CONNECTION_SOURCE will eventually be
removed by the ReferenceQueueThread.

2. no connection is allocated. Then the TSCCM is GCed,
   we have a unit test for this. But how are the open
   connections closed in this scenario? I didn't see a
   finalizer that would close them.

Currently there is nothing that closes threads other than shutdown.
Not sure if we'd want to put this in a finalizer or not.  In general I
have always avoided using them but perhaps this would be a good use
case.

I have also attached changes to the LostConnWorker that should
alleviate the issue with the GC test case.  Once this change is made I
think you'll be able to remove all of the code related to the
ReferenceQueueThread.  After that is done the only static code left is
related to ALL_CONNECTION_MANAGERS.  Is the plan to keep or remove
this code?

Mike
Index: C:/Documents and Settings/Michael/My Documents/HttpClient/HttpComponents-HttpClient/module-client/src/main/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java
===================================================================
--- C:/Documents and Settings/Michael/My Documents/HttpClient/HttpComponents-HttpClient/module-client/src/main/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java	(revision 558525)
+++ C:/Documents and Settings/Michael/My Documents/HttpClient/HttpComponents-HttpClient/module-client/src/main/java/org/apache/http/impl/conn/ThreadSafeClientConnManager.java	(working copy)
@@ -707,17 +707,12 @@
          * Creates a new connection pool.
          */
         private ConnectionPool() {
-            //@@@ currently must be false, otherwise the TSCCM
-            //@@@ will not be garbage collected in the unit test...
-            boolean conngc = false; //@@@ check parameters to decide
-            if (conngc) {
-                refQueue = new ReferenceQueue();
-                refWorker = new LostConnWorker(this);
-                Thread t = new Thread(refWorker); //@@@ use a thread factory
-                t.setDaemon(true);
-                t.setName("LostConnWorker/"+ThreadSafeClientConnManager.this);
-                t.start();
-            }
+            refQueue = new ReferenceQueue();
+            refWorker = new LostConnWorker(this);
+            Thread t = new Thread(refWorker); //@@@ use a thread factory
+            t.setDaemon(true);
+            t.setName("LostConnWorker/"+ThreadSafeClientConnManager.this);
+            t.start();
         }
 
         /**
@@ -1217,7 +1212,12 @@
 
         private volatile Thread workerThread;
 
-        private final ConnectionPool connPool;
+        /**
+         * Weak reference to the [EMAIL PROTECTED] ConnectionPool} for which this worker is processing
+         * entries.  Must be a weak reference to allow the pool and associated
+         * connection manager to be GCed. 
+         */
+        private final WeakReference connPoolRef;
 
 
         /**
@@ -1227,7 +1227,7 @@
          *              and in which to reclaim the lost connections
          */
         public LostConnWorker(ConnectionPool pool) {
-            this.connPool = pool;
+            this.connPoolRef = new WeakReference(pool);
         }
 
 
@@ -1254,12 +1254,14 @@
                 this.workerThread = Thread.currentThread();
             }
 
-            while (this.workerThread == Thread.currentThread()) {
+            while (this.workerThread == Thread.currentThread() && connPoolRef.get() != null) {
                 try {
                     // remove the next reference and process it
-                    Reference ref = connPool.refQueue.remove();
+                    // This code is intentionally obtuse to avoid creating a direct reference
+                    // to the ConnectionPool
+                    Reference ref = ((ConnectionPool) connPoolRef.get()).refQueue.remove();
                     if (ref instanceof PoolEntryRef) {
-                        connPool.handleReference((PoolEntryRef) ref);
+                        ((ConnectionPool) connPoolRef.get()).handleReference((PoolEntryRef) ref);
                     }
                 } catch (InterruptedException e) {
                     LOG.debug("LostConnWorker interrupted", e);
@@ -1267,7 +1269,7 @@
             }
         }
 
-    } // class ReferenceQueueThread
+    } // class LostConnWorker
 
 
     /**
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to