You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Phil Steitz (JIRA)" <ji...@apache.org> on 2011/03/10 15:49:59 UTC

[jira] Commented: (POOL-184) Deadlock in GenericObjectPool. Between borrowObject() and evict()

    [ https://issues.apache.org/jira/browse/POOL-184?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13005085#comment-13005085 ] 

Phil Steitz commented on POOL-184:
----------------------------------

Thanks for reporting this and thanks especially for providing a test case.  I am attaching a thread dump during a stalled execution.

I think what is going on here is not deadlock, but inappropriate starvation.  With maxActive set to 1 (or whenever maxActive is about to be attained by a borrowObject with one idle instance in the pool), if one thread does a borrow while the evictor is visiting the idle instance, the borrowing thread will stall until another thread does a borrow or return.  When there is only one active thread, this will never happen, so the test program stalls.

If my analysis is correct, this is a bug, which is caused by the fact that evict() temporarily removes idle instances being examined, but does not call allocate() when it returns them.  The stall here happens when the borrowing thread makes its request when evict is examining the idle instance.  It never gets notified when the instance is returned to the pool. 

A simple fix is to insert an allocate() at the end of evict().  We need to verify though that this will not cause any other problems.

> Deadlock in GenericObjectPool. Between borrowObject() and evict()
> -----------------------------------------------------------------
>
>                 Key: POOL-184
>                 URL: https://issues.apache.org/jira/browse/POOL-184
>             Project: Commons Pool
>          Issue Type: Bug
>    Affects Versions: 1.5.5
>         Environment: java 1.6.0_24
> Ubuntu 10.10
>            Reporter: Adrian Nistor
>         Attachments: Test01.java
>
>
> Hi,
> I am encountering a deadlock in GenericObjectPool. It appears in version 1.5.5 
> and also in revision 1079385 (March 8th 2011).
> The deadlock manifests when calling borrowObject() and evict() in parallel. I 
> have inlined a test that exposes this problem. For this test, the expected 
> output is:
> Expected output:
> 0
> 1
> 2
> 3
> 4
> .....
> 498
> 499
> DONE
> But when the bug manifests (almost always for this test), the output is:
> Bug output:
> 0
> 1
> 2
> 3
> 4
> When the bug manifests, the test does not finish, it just gets stuck after
> printing several values (in this run: 0 1 2 3 4, but in other runs may be
> 0 1 2 .. 18 or 0 1 2 or some other value).
> When the loop limit is small (e.g., 11 instead of 5000), the test does finish.
> Also, when running sequentially:
>  
>     Pool.borrowObject();
>     Pool.evict();
> or vice-versa
>     Pool.evict();
>     Pool.borrowObject();
> the test still finishes. 
> Is this a bug? Is there a patch for it?
> Thanks!
> Adrian
> ================================================================================
> This test is for version 1.5.5. For revision 1079385 one should replace 
> setMaxActive() with setMaxTotal()
> ================================================================================
> package org.apache.commons.pool.impl;
> import org.apache.commons.pool.PoolableObjectFactory;
> public class Test01 
> {
>     public static void main(String[] args) throws Exception 
>     {
>         Test01 test = new Test01();
>         test.test();
>     }
>     
>     SimpleFactory Factory = null;
>     GenericObjectPool Pool = null;
>     Object Obj = null;
>     public void test() throws Exception 
>     {
>         Factory = new SimpleFactory();
>         Pool = new GenericObjectPool(Factory);
>         Pool.setMaxActive(1);
>         Pool.addObject();
>         
>         for(int i=0; i<5000; i++)
>         {
>             Thread one = new MyThread(1);
>             Thread two = new MyThread(2);
>             one.start();
>             two.start();
>             one.join();
>             two.join();
>             
>             Pool.returnObject(Obj);
>             if(i%10==0)
>             {
>                 System.out.println(i/10);
>             }
>         }
>         System.out.println("DONE");
>     }
>     private class MyThread extends Thread 
>     {
>         int _tid;
>         public MyThread(int tid) 
>         {
>             _tid = tid;
>         }
>         public void run() 
>         {
>             try 
>             {
>                 if(_tid == 1) 
>                 {
>                     Obj = Pool.borrowObject();
>                 }
>                 if (_tid == 2) 
>                 {
>                     try
>                     {
>                         Pool.evict();
>                     } catch (Exception e) {}
>                 }
>             } 
>             catch(Exception e) 
>             {
>                 throw new RuntimeException(e);
>             }
>         }
>     }
>     private class SimpleFactory implements PoolableObjectFactory
>     {
>         public SimpleFactory() {}
>         public Object makeObject() { return new String("testing"); }
>         public void destroyObject(Object obj) {}
>         public boolean validateObject(Object obj) {return true;}
>         public void activateObject(Object obj) throws Exception {}
>         public void passivateObject(Object obj) throws Exception {}
>         public boolean isThrowExceptionOnActivate() {return true;}
>     }
> }
> ================================================================================

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira