[
https://issues.apache.org/jira/browse/POOL-315?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15591432#comment-15591432
]
Buğra Gedik commented on POOL-315:
----------------------------------
{code}
package com.unscrambl.drive;
import static org.junit.Assert.assertFalse;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.Test;
public class PoolTest
{
private static final CharSequence COMMONS_POOL_EVICTIONS_TIMER_THREAD_NAME =
"commons-pool-EvictionTimer";
private static final long EVICTION_PERIOD_IN_MILLIS = 100;
private static class Foo
{
}
private static class PooledFooFactory implements PooledObjectFactory<Foo>
{
private static final long VALIDATION_WAIT_IN_MILLIS = 1000;
@Override
public PooledObject<Foo> makeObject() throws Exception
{
return new DefaultPooledObject<>(new Foo());
}
@Override
public void destroyObject(
PooledObject<Foo> pooledObject) throws Exception
{
}
@Override
public boolean validateObject(
PooledObject<Foo> pooledObject)
{
try
{
Thread.sleep(VALIDATION_WAIT_IN_MILLIS);
}
catch (final InterruptedException e)
{
Thread.interrupted();
}
return false;
}
@Override
public void activateObject(
PooledObject<Foo> pooledObject) throws Exception
{
}
@Override
public void passivateObject(
PooledObject<Foo> pooledObject) throws Exception
{
}
}
@Test
public void testPool() throws Exception
{
final GenericObjectPoolConfig poolConfig =
new GenericObjectPoolConfig();
poolConfig.setTestWhileIdle(true /* testWhileIdle */);
final PooledFooFactory pooledFooFactory = new PooledFooFactory();
GenericObjectPool<Foo> pool = null;
try
{
pool = new GenericObjectPool<>(pooledFooFactory, poolConfig);
pool.setTimeBetweenEvictionRunsMillis(EVICTION_PERIOD_IN_MILLIS);
pool.addObject();
try
{
Thread.sleep(EVICTION_PERIOD_IN_MILLIS);
}
catch (final InterruptedException e)
{
Thread.interrupted();
}
}
finally
{
if (pool != null)
{
pool.close();
}
}
final Thread[] threads = new Thread[Thread.activeCount()];
Thread.enumerate(threads);
for (final Thread thread : threads)
{
if (thread == null)
{
continue;
}
assertFalse(thread.getName()
.contains(COMMONS_POOL_EVICTIONS_TIMER_THREAD_NAME));
}
}
}
{code}
> GenericObjectPool close() does not wait for the current eviction task
> ---------------------------------------------------------------------
>
> Key: POOL-315
> URL: https://issues.apache.org/jira/browse/POOL-315
> Project: Commons Pool
> Issue Type: Bug
> Reporter: Buğra Gedik
>
> The {{close}} method is implemented as follows:
> {code}
> public void close() {
> if(!this.isClosed()) {
> Object var1 = this.closeLock;
> synchronized(this.closeLock) {
> if(!this.isClosed()) {
> this.startEvictor(-1L);
> this.closed = true;
> this.clear();
> this.jmxUnregister();
> this.idleObjects.interuptTakeWaiters();
> }
> }
> }
> }
> {code}
> The line {{this.startEvictor(-1L);}} calls
> {{EvictionTimer.cancel(this.evictor);}} from {{BaseGenericObjectPool}} and
> that in turn calls the following method in {{EvictionTimer}}:
> {code}
> static synchronized void cancel(TimerTask task) {
> task.cancel();
> --_usageCount;
> if(_usageCount == 0) {
> _timer.cancel();
> _timer = null;
> }
> }
> {code}
> Here, {{_timer}} is a {{java.util.TimerTask}}. If you look at the
> documentation of it, you'll see that it does not block on the currently
> executing task. Even though {{task.cancel()}} is called, there is no code to
> wait for it to complete. The end result is that, even if you close the pool,
> there may still be an eviction thread running. Yes, it will eventually go
> away, but in some rare cases it takes a bit of time to go away.
> When running code under Tomcat, this results in the
> {{"commons-pool-EvictionTimer"}} thread (created in the class
> {{EvictionTimer}}) to be reported as leaking, despite the pool being closed.
> This happens rarely, since most of the time the timer thread goes away before
> Tomcat checks for leaking threads.
> In my opinion a fix can be put into {{startEvictor}} in
> {{BaseGenericObjectPool}}:
> {code}
> final void startEvictor(long delay) {
> synchronized (evictionLock) {
> if (null != evictor) {
> EvictionTimer.cancel(evictor);
> // HERE: evictor.waitForCompletion();
> evictor = null;
> evictionIterator = null;
> }
> if (delay > 0) {
> evictor = new Evictor();
> EvictionTimer.schedule(evictor, delay, delay);
> }
> }
> }
> {code}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)