Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 8A781200BB6 for ; Thu, 20 Oct 2016 12:20:00 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 890DF160ADB; Thu, 20 Oct 2016 10:20:00 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id AAE81160AE0 for ; Thu, 20 Oct 2016 12:19:59 +0200 (CEST) Received: (qmail 41883 invoked by uid 500); 20 Oct 2016 10:19:58 -0000 Mailing-List: contact issues-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: issues@commons.apache.org Delivered-To: mailing list issues@commons.apache.org Received: (qmail 41854 invoked by uid 99); 20 Oct 2016 10:19:58 -0000 Received: from arcas.apache.org (HELO arcas) (140.211.11.28) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 20 Oct 2016 10:19:58 +0000 Received: from arcas.apache.org (localhost [127.0.0.1]) by arcas (Postfix) with ESMTP id 751242C0D52 for ; Thu, 20 Oct 2016 10:19:58 +0000 (UTC) Date: Thu, 20 Oct 2016 10:19:58 +0000 (UTC) From: =?utf-8?Q?Bu=C4=9Fra_Gedik_=28JIRA=29?= To: issues@commons.apache.org Message-ID: In-Reply-To: References: Subject: [jira] [Commented] (POOL-315) GenericObjectPool close() does not wait for the current eviction task MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-JIRA-FingerPrint: 30527f35849b9dde25b450d4833f0394 archived-at: Thu, 20 Oct 2016 10:20:00 -0000 [ https://issues.apache.org/jira/browse/POOL-315?page=3Dcom.atlassian.j= ira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=3D155914= 33#comment-15591433 ]=20 Bu=C4=9Fra 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_N= AME =3D "commons-pool-EvictionTimer"; private static final long EVICTION_PERIOD_IN_MILLIS =3D 100; private static class Foo { } private static class PooledFooFactory implements PooledObjectFactory { private static final long VALIDATION_WAIT_IN_MILLIS =3D 1000; @Override public PooledObject makeObject() throws Exception { return new DefaultPooledObject<>(new Foo()); } @Override public void destroyObject( PooledObject pooledObject) throws Exception { } @Override public boolean validateObject( PooledObject pooledObject) { try { Thread.sleep(VALIDATION_WAIT_IN_MILLIS); } catch (final InterruptedException e) { Thread.interrupted(); } return false; } @Override public void activateObject( PooledObject pooledObject) throws Exception { } @Override public void passivateObject( PooledObject pooledObject) throws Exception { } } @Test public void testPool() throws Exception { final GenericObjectPoolConfig poolConfig =3D new GenericObjectPoolConfig(); poolConfig.setTestWhileIdle(true /* testWhileIdle */); final PooledFooFactory pooledFooFactory =3D new PooledFooFactory(); GenericObjectPool pool =3D null; try { pool =3D 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 !=3D null) { pool.close(); } } final Thread[] threads =3D new Thread[Thread.activeCount()]; Thread.enumerate(threads); for (final Thread thread : threads) { if (thread =3D=3D 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=C4=9Fra Gedik > > The {{close}} method is implemented as follows: > {code} > public void close() { > if(!this.isClosed()) { > Object var1 =3D this.closeLock; > synchronized(this.closeLock) { > if(!this.isClosed()) { > this.startEvictor(-1L); > this.closed =3D true; > this.clear(); > this.jmxUnregister(); > this.idleObjects.interuptTakeWaiters(); > } > } > } > } > {code} > The line {{this.startEvictor(-1L);}} calls {{EvictionTimer.cancel(this.ev= ictor);}} from {{BaseGenericObjectPool}} and that in turn calls the followi= ng method in {{EvictionTimer}}: > {code} > static synchronized void cancel(TimerTask task) { > task.cancel(); > --_usageCount; > if(_usageCount =3D=3D 0) { > _timer.cancel(); > _timer =3D null; > } > } > {code} > Here, {{_timer}} is a {{java.util.TimerTask}}. If you look at the documen= tation 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, b= ut in some rare cases it takes a bit of time to go away. > When running code under Tomcat, this results in the {{"commons-pool-Evict= ionTimer"}} 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 thr= eads. > In my opinion a fix can be put into {{startEvictor}} in {{BaseGenericObje= ctPool}}: > {code} > final void startEvictor(long delay) { > synchronized (evictionLock) { > if (null !=3D evictor) { > EvictionTimer.cancel(evictor); > // HERE: evictor.waitForCompletion(); > evictor =3D null; > evictionIterator =3D null; > } > if (delay > 0) { > evictor =3D new Evictor(); > EvictionTimer.schedule(evictor, delay, delay); > } > } > } > {code} -- This message was sent by Atlassian JIRA (v6.3.4#6332)