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

Dmitry Potapov updated HTTPASYNC-56:
------------------------------------

    Description: 
How it looks like:
1. Theads A and B calls CloseableHttpAsyncClient.execute() of the same 
CloseableHttpAsyncClient (problem may reproduce on two separate clients sharing 
single connection pool)
2. Each CloseableHttpAsyncClient.execute in turn calls 
InternalHttpAsyncClient.execute() which creates 
DefaultClientExchangeHandlerImpl instance and calls 
DefaultClientExchangeHandlerImpl.start(), which is synchronized
3. At this point, we have two DefaultClientExchangeHandlerImpl with locked 
monitors, let these instances have names AH and BH.
4. DefaultClientExchangeHandlerImpl.start() calls requestConnection(), which in 
turn calls PoolingNHttpClientConnectionManager.requestConnection()
5. At thread A: AbstractNIOConnPool.lease() adds completed request to the 
completedRequests queue (line 271). This request callback has reference to the 
AH
6. At thread B: AbstractNIOConnPool.lease() adds completed request to the 
completedRequests queue. This request callback has reference to BH
7. At thread B: AbstractNIOConnPool.fireCallbacks() is called. It polls AH from 
completedRequests and calls AH callback, which tries to enter AH monitor and 
locks, because this monitor is already locked.
8. At thread A: AbstractNIOConnPool.fireCallbacks() is called. It polls BH from 
completedRequests (AH was polled at step 7) and calls BH callback, which tries 
to enter BH monitor and locks, because this monitor is already locked.

At this point we have threads A and B deadlocked.

I have obvious solution for this particular dead-lock: make 
DefaultClientExchangeHandlerImpl.start() not synchronized, because this object 
created only at single point, and .start() is called immediately after 
construction.

I'm not sure that there is no problems in other scenarious where 
.fireCallbacks() involved, because 
DefaultClientExchangeHandlerImpl.requestConnection() may be called from other 
synchronized methods.

  was:
How it looks like:
1. Theads A and B calls CloseableHttpAsyncClient.execute()
2. Each CloseableHttpAsyncClient in turn calls 
InternalHttpAsyncClient.execute() which creates 
DefaultClientExchangeHandlerImpl instance and calls 
DefaultClientExchangeHandlerImpl.start(), which is synchronized
3. At this point, we have two DefaultClientExchangeHandlerImpl with locked 
monitors, let these instances have names AH and BH.
4. DefaultClientExchangeHandlerImpl.start() calls requestConnection(), which in 
turn calls PoolingNHttpClientConnectionManager.requestConnection()
5. At thread A: AbstractNIOConnPool.lease() adds completed request to the 
completedRequests queue (line 271). This request callback has reference to the 
AH
6. At thread B: AbstractNIOConnPool.lease() adds completed request to the 
completedRequests queue. This request callback has reference to BH
7. At thread B: AbstractNIOConnPool.fireCallbacks() is called. It polls AH from 
completedRequests and calls AH callback, which tries to enter AH monitor and 
locks, because this monitor is already locked.
8. At thread A: AbstractNIOConnPool.fireCallbacks() is called. It polls BH from 
completedRequests (AH was polled at step 7) and calls BH callback, which tries 
to enter BH monitor and locks, because this monitor is already locked.

At this point we have threads A and B deadlocked.

I have obvious solution for this particular dead-lock: make 
DefaultClientExchangeHandlerImpl.start() not synchronized, because this object 
created only at single point, and .start() is called immediately after 
construction.

I'm not sure that there is no problems in other scenarious where 
.fireCallbacks() involved, because 
DefaultClientExchangeHandlerImpl.requestConnection() may be called from other 
synchronized methods.


> Deadlock in DefaultClientExchangeHandlerImpl.start()
> ----------------------------------------------------
>
>                 Key: HTTPASYNC-56
>                 URL: https://issues.apache.org/jira/browse/HTTPASYNC-56
>             Project: HttpComponents HttpAsyncClient
>          Issue Type: Bug
>    Affects Versions: 4.0-beta4
>            Reporter: Dmitry Potapov
>
> How it looks like:
> 1. Theads A and B calls CloseableHttpAsyncClient.execute() of the same 
> CloseableHttpAsyncClient (problem may reproduce on two separate clients 
> sharing single connection pool)
> 2. Each CloseableHttpAsyncClient.execute in turn calls 
> InternalHttpAsyncClient.execute() which creates 
> DefaultClientExchangeHandlerImpl instance and calls 
> DefaultClientExchangeHandlerImpl.start(), which is synchronized
> 3. At this point, we have two DefaultClientExchangeHandlerImpl with locked 
> monitors, let these instances have names AH and BH.
> 4. DefaultClientExchangeHandlerImpl.start() calls requestConnection(), which 
> in turn calls PoolingNHttpClientConnectionManager.requestConnection()
> 5. At thread A: AbstractNIOConnPool.lease() adds completed request to the 
> completedRequests queue (line 271). This request callback has reference to 
> the AH
> 6. At thread B: AbstractNIOConnPool.lease() adds completed request to the 
> completedRequests queue. This request callback has reference to BH
> 7. At thread B: AbstractNIOConnPool.fireCallbacks() is called. It polls AH 
> from completedRequests and calls AH callback, which tries to enter AH monitor 
> and locks, because this monitor is already locked.
> 8. At thread A: AbstractNIOConnPool.fireCallbacks() is called. It polls BH 
> from completedRequests (AH was polled at step 7) and calls BH callback, which 
> tries to enter BH monitor and locks, because this monitor is already locked.
> At this point we have threads A and B deadlocked.
> I have obvious solution for this particular dead-lock: make 
> DefaultClientExchangeHandlerImpl.start() not synchronized, because this 
> object created only at single point, and .start() is called immediately after 
> construction.
> I'm not sure that there is no problems in other scenarious where 
> .fireCallbacks() involved, because 
> DefaultClientExchangeHandlerImpl.requestConnection() may be called from other 
> synchronized methods.



--
This message was sent by Atlassian JIRA
(v6.1#6144)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to