java.util.concurrent provides everything you need. If I understand your question correctly, you have the following requirements:
You want to send requests and immediately (within reasonable limits) process the result of the request (response). Well, I believe that you have already seen a solution to your problem: java.util.concurrent.CompletionService.
This service, which rather combines Executor and BlockingQueue to handle Runnable and / or Callable tasks. BlockingQueue is used to complete completed tasks, which you can expect to wait for the next thread until the task completes its task (this is done by calling the take () method) of the CompletionService object.
As previous posters noted, share with the Contractor and create a CompletionService for each request. This may seem like an expensive affair, but think again that CS is simply collaborating with Contractor and BlockingQueue. Since you are using the most expensive object to instantiate, i.e. Contractor, I think you will find that it is a very reasonable cost.
However ... all of this suggests that you still have a problem, and that problem seems to be separating request processing from response processing. This can be approached by creating a separate service that will exclusively process requests for all requests or for a specific type of request.
Here is an example: (Note: this implies that the Request object implements the Callable interface, which should return a Response type ... the details that I skipped for this simple example).
class RequestHandler { RequestHandler(ExecutorService responseExecutor, ResponseHandler responseHandler) { this.responseQueue = ... this.executor = ... } public void acceptRequest(List<Request> requestList) { for(Request req : requestList) { Response response = executor.submit(req); responseHandler.handleResponse(response); } } } class ResponseHandler { ReentrantLock lock; ResponseHandler(ExecutorService responseExecutor) { ... } public void handleResponse(Response res) { lock.lock() { try { responseExecutor.submit( new ResponseWorker(res) ); } finally { lock.unlock(); } } private static class ResponseWorker implements Runnable { ResponseWorker(Response response) { response = ... } void processResponse() {
A few things to remember: one, the ExecutorService executes Callables or Runnables from the lock queue; your RequestHandler receives the task, and those that are in the queue in the Executor are processed as soon as possible. The same thing happens in your ResponseHandler; a response will be received, and as soon as this SEPARATE executor can, he will process this response. In short, you have two executors working at the same time: one on the Request objects, the other on the Response objects.