Is this RESTEasy doing this, or a user app written against RESTEasy? AFAIK RESTEasy won't start its own threads after suspending, so it sounds like this might be a user app that has created the multiple threads?
Ah the OP now says they can change their error handling, so not a function of RESTEasy.... but still something applications can do.
In general you should unblock the thread, because blocking a thread indefinitely is not nice.
yes - but how to do so safely.
This case sounds like it's the applications fault, but consider an app that calls start async, ...
... Consider the following case:
I think your example is a simple reduction of the generalization of this issue. Ie that we have undefined behavior with regards to parallelism between an incomplete IO operation (eg blocking read by non container thread) and container dispatched actions (onTimeout in Stuart's example and onComplete in mine).
As it stands I don't think we can fix this with a simple clarification, as IMHO there are fundamental issues here.
The paths I can see to make this better:
- Just describe these situations, say they are undefined behaviour and point to patterns to avoid them.
- We say that containers should not dispatch any action (onComplete, onError, onTimeout) whilst an IO operation is in progress. This probably would help but would likely result in a great big lock that needs to be grabbed for every operation. It also might make it harder to have independent read/write sides
- Offer a new mechanism of a Runnable that is executed or failed with the same serialized semantics of a container action. Ie the Runnable will not be executed in parallel with any container thread calling any dispatch or onFooBar callback. Effectively make any Runnable the equivalent of a thread dispatched into the servlet, so that any complete actions only take place once it returns.
Note also, I think there is a related problem with async IO operations. If isReady() has returned false, then should onError be called if complete() is called? Or should the complete() be deferred until after the IO operation has timed out? Either way it is kind of ugly as the caller of complete will have has setup the response as they want it and the onError call is likely to write all over that or even call dispatch. So perhaps in this case it is better not to call onError and just say that a call to onComplete is a signal of the cancellation of any outstanding async IO operations.
cheers