0

I have a third-party MyService class which is not thread safe, I have the same issue as this with one difference: I need to submit Callables not Runnables.

With a regular ThreadPoolExecutor I would have done this:

ExecutorService executor = Executors.newFixedThreadPool(8);
// later in another thread
Future<String> result = executor.submit(() -> {
     // compute return value then return it
     return computed value
})

I would have then waited on the result future to get the result of callable.

But ExecutorService doesn't have a way to associate an object with each thread and the answer to the question above doesn't consider that the worker thread needs to communicate back to the Thread who submitted the task.

Using ThreadLocal has the obvious drawback at shutdown phase, I thought of a Map of Thread Ids to the results they need but ConcurrentHashMap doesn't provide a method that blocks current thread waiting for a key to be added and this question doesn't give me a good answer: BlockingQueue<Map.Entry> is not what I need here and the BlockingMap library linked is very old.

So How do I achieve what I want ?

niceman
  • 2,653
  • 29
  • 57
  • Have you tried passing some kind of thread-safe object to the Callable’s constructor? That way, you could get the computation result. – Oliver Marienfeld Oct 08 '20 at 18:27
  • @rowing-ghoul I can't pass a thread-safe object, also I need the threads in the thread pool to own `MyService` objects not to create it in connection thread and pass it to. – niceman Oct 09 '20 at 09:15
  • @rowing-ghoul and I need to create multiple objects for each thread at startup not to create those objects in every request from connection threads – niceman Oct 09 '20 at 09:16

1 Answers1

0

I found a way, this solution is taken from Executors jdk implementation code. in short we use a Future<Result> to communicate back to the request thread like this:

class Task<T> extends CompletableFuture<T>
// in worker thread
MyService service = new MyServiceImpl();
while(!!Thread.currentThread().isInterrupted()){
     Task<T> task = blockingQueue.take();
     T result = ... // compute result
     task.complete(result)
}
// in request thread
Task<T> newTask = new Task<>();
blockingQueue.put(newTask)
return newTask.get() <--- ofcourse you can do others things with the future
niceman
  • 2,653
  • 29
  • 57