[ 
https://issues.apache.org/jira/browse/POOL-149?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

shuyang.zhou updated POOL-149:
------------------------------

    Attachment: BugTest.java

Ok, there is no way to force the bad case to happen in a unit test.
I created a test case, and with it you can just hope the bug happens.

And i tested it several times, it always happens. But maybe you need to run it 
several time to get your luck.

Here is the instruction:
1)Run the test case, and look at your output console
2)Wait until it stops output timestamp(If you test case quit successfully, you 
need to restart from 1))
3)Use VisualVM to take a thread dump and heap dump

>From the thread dump you should able to find one pooled thread wait on 
>GenericObjectPool for ever like this:
"pool-267-thread-10" prio=10 tid=0x00007f58c4300800 nid=0x2892 in Object.wait() 
[0x00007f58c91a2000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:485)
        at 
org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1103)
        - locked <0x00007f58fb042db0> (a 
org.apache.commons.pool.impl.GenericObjectPool$Latch)
        at BugTest$TestJob.run(BugTest.java:72)
        at 
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
        at java.util.concurrent.FutureTask.run(FutureTask.java:138)
        at 
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at 
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:619)

   Locked ownable synchronizers:
        - <0x00007f58fa67ff10> (a 
java.util.concurrent.locks.ReentrantLock$NonfairSync)

>From the heap dump you should able to see the GenericObjectPool is empty.

There is another way to see this bug easily, but you need a multithread enabled 
debuger, for example, Netbeans(See 
http://www.netbeans.org/kb/docs/java/debug-multithreaded.html)
In the test case set TEST_THREAD_NUM=2, MAX_ACTIVE=1, run the debuger with the 
instruction in ticket description, you can see how this bug happens easily.

> A serious concurrent bug can cause deadlock when Pool exhausted and borrowed 
> objects are invalid
> ------------------------------------------------------------------------------------------------
>
>                 Key: POOL-149
>                 URL: https://issues.apache.org/jira/browse/POOL-149
>             Project: Commons Pool
>          Issue Type: Bug
>            Reporter: shuyang.zhou
>            Priority: Critical
>         Attachments: BugTest.java
>
>
> This bug will happen when the pool is in exhausted state and the borrowed 
> object are invalid.
> Let's go through a simple scenario:
> 1)A GenericObjectPool with _maxActive==1, 
> whenExhaustedAction==WHEN_EXHAUSTED_BLOCK
> 2)Two threads using that pool, called thread1 and thread2
> Here is error path:
> 1)thread1 calls pool.borrowObject() to get the object out of the pool
> //now the pool is exhausted
> 2)thread2 calls pool.borrowObject(), adds a new latch to the 
> _allocationQueue, but before it enters the synchronized block for 
> WHEN_EXHAUSTED_BLOCK(GenericObjectPool line 1099 revision 806215), 
> context-switch happens
> 3)thread1 checks the object from pool, and decides to invalidate it. So it 
> calls pool.invalidateObject(), which calls allocate(), then calls 
> latch.notify(), but currently no thread is waiting on this latch.(thread2 has 
> not enter the wait synchronized block yet).
> 4)Then thread2 will wait there for ever.(it just missed the notify)

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to