Java Executor partial shutdown - java

Lets have one classic Executor in application. Many parts of application use this executor for some computations, each computation can be cancelled, for this I can call shutdown() or shutdownNow() on Executor.
But I want to shutdown only part of tasks in Executor. Sadly I can't have access to Future objects, they are private part of computation implementation (actually computation is backed by actor framework jetlang)
I want something like Executor wrapper, which I could pass to computation and which should be backed by real Executor. Something like this:
// main application executor
Executor applicationExecutor = Executors.newCachedThreadPool();
// starting computation
Executor computationExecutor = new ExecutorWrapper(applicationExecutor);
Computation computation = new Computation(computationExecutor);
computation.start();
// cancelling computation
computation.cancel();
// shutting down only computation tasks
computationExecutor.shutdown();
// applicationExecutor remains running and happy
Or any other idea?

For those, who wants good ends: there is final solution, partially based of Ivan Sopov's answer. Luckily jetlang uses for running its tasks only Executor interface (not ExecutorService), so I make wrapper class which supports stopping tasks created only by this wrapper.
static class StoppableExecutor implements Executor {
final ExecutorService executor;
final List<Future<?>> futures = Lists.newArrayList();
boolean stopped;
public StoppableExecutor(ExecutorService executor) {
this.executor = executor;
}
void stop() {
this.stopped = true;
synchronized (futures) {
for (Iterator<Future<?>> iterator = futures.iterator(); iterator.hasNext();) {
Future<?> future = iterator.next();
if (!future.isDone() && !future.isCancelled()) {
System.out.println(future.cancel(true));
}
}
futures.clear();
}
}
#Override
public void execute(Runnable command) {
if (!stopped) {
synchronized (futures) {
Future<?> newFuture = executor.submit(command);
for (Iterator<Future<?>> iterator = futures.iterator(); iterator.hasNext();) {
Future<?> future = iterator.next();
if (future.isDone() || future.isCancelled())
iterator.remove();
}
futures.add(newFuture);
}
}
}
}
Using this is pretty straightforward:
ExecutorService service = Executors.newFixedThreadPool(5);
StoppableExecutor executor = new StoppableExecutor(service);
// doing some actor stuff with executor instance
PoolFiberFactory factory = new PoolFiberFactory(executor);
// stopping tasks only created on executor instance
// executor service is happily running other tasks
executor.stop();
That's all. Works nice.

How about having your Computation be a Runnable (and run using the provided Executor) until a boolean flag is set? Something along the lines of :
public class Computation
{
boolean volatile stopped;
public void run(){
while(!stopped){
//do magic
}
public void cancel)(){stopped=true;}
}
What you are doing is essentially stopping the thread. However, it does not get garbage-collected, but is instead re-used because it is managed by the Executor. Look up "what is the proper way to stop a thread?".
EDIT: please note the code above is quite primitive in the sense it assumes the body of the while loop takes a short amount of time. If it does not, the check will be executed infrequently and you will notice a delay between canceling a task and it actually stopping.

Something like this?
You may do partial shutdown:
for (Future<?> future : %ExecutorServiceWrapperInstance%.getFutures()) {
if (%CONDITION%) {
future.cancel(true);
}
}
Here is the code:
package com.sopovs.moradanen;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class ExecutorServiceWrapper implements ExecutorService {
private final ExecutorService realService;
private List<Future<?>> futures = new ArrayList<Future<?>>();
public ExecutorServiceWrapper(ExecutorService realService) {
this.realService = realService;
}
#Override
public void execute(Runnable command) {
realService.execute(command);
}
#Override
public void shutdown() {
realService.shutdown();
}
#Override
public List<Runnable> shutdownNow() {
return realService.shutdownNow();
}
#Override
public boolean isShutdown() {
return realService.isShutdown();
}
#Override
public boolean isTerminated() {
return realService.isTerminated();
}
#Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return realService.awaitTermination(timeout, unit);
}
#Override
public <T> Future<T> submit(Callable<T> task) {
Future<T> future = realService.submit(task);
synchronized (this) {
futures.add(future);
}
return future;
}
public synchronized List<Future<?>> getFutures() {
return Collections.unmodifiableList(futures);
}
#Override
public <T> Future<T> submit(Runnable task, T result) {
Future<T> future = realService.submit(task, result);
synchronized (this) {
futures.add(future);
}
return future;
}
#Override
public Future<?> submit(Runnable task) {
Future<?> future = realService.submit(task);
synchronized (this) {
futures.add(future);
}
return future;
}
#Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
List<Future<T>> future = realService.invokeAll(tasks);
synchronized (this) {
futures.addAll(future);
}
return future;
}
#Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException {
List<Future<T>> future = realService.invokeAll(tasks, timeout, unit);
synchronized (this) {
futures.addAll(future);
}
return future;
}
#Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
//don't know what to do here. Maybe this method is not needed by the framework
//than just throw new NotImplementedException();
return realService.invokeAny(tasks);
}
#Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
//don't know what to do here. Maybe this method is not needed by the framework
//than just throw new NotImplementedException();
return realService.invokeAny(tasks, timeout, unit);
}
}

Related

what is the advantage of using FutureTask over Callable?

There are two approaches to submitting and polling task for result
FutureTask futureTask = new FutureTask<String>(callable);
Use combination of Callable and Future and submit on ExecutorService. Retrieve result using future.get().
Future future = service.submit(callable);
Use FutureTask. This will wrap Callable and then retrieve result using FutureTask.
service.execute(task);
What is the advantage of using FutureTask over Callable + Future combination ?
Almost certainly none at all. A quick browse on GrepCode of the AbstractExecutorService shows each of these methods are simply helper methods that ultimately wrap the Callable/Runnable in a Future for you.
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
public Future<?> submit(Runnable task) {
// ...
RunnableFuture<Object> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
// ...
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Callable<T> task) {
// ...
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
Using Future we can find out the status of the Callable task and get the returned Object. It provides get() method that can wait for the Callable to finish and then return the result.
Future provides cancel() method to cancel the associated Callable task. There is an overloaded version of get() method where we can specify the time to wait for the result, it’s useful to avoid current thread getting blocked for longer time. There are isDone() and isCancelled() methods to find out the current status of associated Callable task.
Here is a simple example of Callable task that returns the name of thread executing the task after one second. We are using Executor framework to execute 100 tasks in parallel and use Future to get the result of the submitted tasks.
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class MyCallable implements Callable<String> {
#Override
public String call() throws Exception {
Thread.sleep(1000);
//return the thread name executing this callable task
return Thread.currentThread().getName();
}
public static void main(String args[]){
//Get ExecutorService from Executors utility class, thread pool size is 10
ExecutorService executor = Executors.newFixedThreadPool(10);
//create a list to hold the Future object associated with Callable
List<Future<String>> list = new ArrayList<Future<String>>();
//Create MyCallable instance
Callable<String> callable = new MyCallable();
for(int i=0; i< 100; i++){
//submit Callable tasks to be executed by thread pool
Future<String> future = executor.submit(callable);
//add Future to the list, we can get return value using Future
list.add(future);
}
for(Future<String> fut : list){
try {
//print the return value of Future, notice the output delay in console
// because Future.get() waits for task to get completed
System.out.println(new Date()+ "::"+fut.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
//shut down the executor service now
executor.shutdown();
}
}
Where as FutureTask is base concrete implementation of Future interface and provides asynchronous processing. It contains the methods to start and cancel a task and also methods that can return the state of the FutureTask as whether it’s completed or cancelled. We need a callable object to create a future task and then we can use Java Thread Pool Executor to process these asynchronously.
Let’s see the example of FutureTask with a simple program.
Since FutureTask requires a callable object, we will create a simple Callable implementation.
public class MyCallable implements Callable<String> {
private long waitTime;
public MyCallable(int timeInMillis){
this.waitTime=timeInMillis;
}
#Override
public String call() throws Exception {
Thread.sleep(waitTime);
//return the thread name executing this callable task
return Thread.currentThread().getName();
}
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class FutureTaskExample {
public static void main(String[] args) {
MyCallable callable1 = new MyCallable(1000);
MyCallable callable2 = new MyCallable(2000);
FutureTask<String> futureTask1 = new FutureTask<String>(callable1);
FutureTask<String> futureTask2 = new FutureTask<String>(callable2);
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(futureTask1);
executor.execute(futureTask2);
while (true) {
try {
if(futureTask1.isDone() && futureTask2.isDone()){
System.out.println("Done");
//shut down executor service
executor.shutdown();
return;
}
if(!futureTask1.isDone()){
//wait indefinitely for future task to complete
System.out.println("FutureTask1 output="+futureTask1.get());
}
System.out.println("Waiting for FutureTask2 to complete");
String s = futureTask2.get(200L, TimeUnit.MILLISECONDS);
if(s !=null){
System.out.println("FutureTask2 output="+s);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}catch(TimeoutException e){
//do nothing
}
}
}
}
FutureTask<T> class contains an additional " done()" method so we can override the done() method, then add the FutureTask object to the ExecutorService, so the done() method will invoke when the FutureTask completed immediately.

ThreadPoolExecutor's queuing behavior customizable to prefer new thread creation over queuing?

ThreadPoolExecutor doc says
If corePoolSize or more threads are running, the Executor always
prefers queuing a request rather than adding a new thread.
If there are more than corePoolSize but less than maximumPoolSize
threads running, a new thread will be created only if the queue is
full.
Is there a way to get the executor to prefer new thread creation until the max is reached even if there are there are more than core size threads, and then start queuing? Tasks would get rejected if the queue reached its maximum size. It would be nice if the timeout setting would kick in and remove threads down to core size after a busy burst has been handled. I see the reason behind preferring to queue so as to allow for throttling; however, this customization would additionally allow the queue to act mainly as a list of tasks yet to be run.
No way to get this exact behavior with a ThreadPoolExecutor.
But, here's a couple solutions:
Consider,
If less than corePoolSize threads are running, a new thread will be created for every item queued until coorPoolSize threads are running.
A new thread will only be created if the queue is full, and less than maximumPoolSize threads are running.
So, wrap a ThreadPoolExecutor in a class which monitors how fast items are being queued. Then, change the core pool size to a higher value when many items are being submitted. This will cause a new thread to be created each time a new item is submitted.
When the submission burst is done, core pool size needs to be manually reduced again so the threads can naturally time out. If you're worried the busy burst could end abruptly, causing the manual method to fail, be sure to use allowCoreThreadTimeout.
Create a fixed thread pool, and allowCoreThreadTimeout
Unfortunately this uses more threads during low submission bursts, and stores no idle threads during zero traffic.
Use the 1st solution if you have the time, need, and inclination as it will handle a wider range of submission frequency and so is a better solution in terms of flexibility.
Otherwise use the 2nd solution.
Just do what Executors.newFixedThreadPool does and set core and max to the same value. Here's the newFixedThreadPool source from Java 6:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
What you can do if you have an existing one:
ThreadPoolExecutor tpe = ... ;
tpe.setCorePoolSize(tpe.getMaxPoolSize());
Edit: As William points out in the comments, this means that all threads are core threads, so none of the threads will time out and terminate. To change this behavior, just use ThreadPoolExecutor.allowCoreThreadTimeout(true). This will make it so that the threads can time out and be swept away when the executor isn't in use.
It seems that your preference is minimal latency during times of low-activity. For that I would just set the corePoolSize to the max and let the extra threads hang around. During high-activity times these threads will be there anyways. During low-activity times their existence won't have that much impact. You can set the core thread timeout if you want them to die though.
That way all the threads will always be available to execute a task as soon as possible.
CustomBlockingQueue
package com.gunjan;
import java.util.concurrent.BlockingQueue;
public abstract class CustomBlockingQueue<E> implements BlockingQueue<E> {
public BlockingQueue<E> blockingQueue;
public CustomBlockingQueue(BlockingQueue blockingQueue) {
this.blockingQueue = blockingQueue;
}
#Override
final public boolean offer(E e) {
return false;
}
final public boolean customOffer(E e) {
return blockingQueue.offer(e);
}
}
ThreadPoolBlockingQueue
package com.gunjan;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
public class ThreadPoolBlockingQueue<E> extends CustomBlockingQueue<E> {
public ThreadPoolBlockingQueue(BlockingQueue blockingQueue) {
super(blockingQueue);
}
#Override
public E remove() {
return this.blockingQueue.remove();
}
#Override
public E poll() {
return this.blockingQueue.poll();
}
#Override
public E element() {
return this.blockingQueue.element();
}
#Override
public E peek() {
return this.blockingQueue.peek();
}
#Override
public int size() {
return this.blockingQueue.size();
}
#Override
public boolean isEmpty() {
return this.blockingQueue.isEmpty();
}
#Override
public Iterator<E> iterator() {
return this.blockingQueue.iterator();
}
#Override
public Object[] toArray() {
return this.blockingQueue.toArray();
}
#Override
public <T> T[] toArray(T[] a) {
return this.blockingQueue.toArray(a);
}
#Override
public boolean containsAll(Collection<?> c) {
return this.blockingQueue.containsAll(c);
}
#Override
public boolean addAll(Collection<? extends E> c) {
return this.blockingQueue.addAll(c);
}
#Override
public boolean removeAll(Collection<?> c) {
return this.blockingQueue.removeAll(c);
}
#Override
public boolean retainAll(Collection<?> c) {
return this.blockingQueue.retainAll(c);
}
#Override
public void clear() {
this.blockingQueue.clear();
}
#Override
public boolean add(E e) {
return this.blockingQueue.add(e);
}
#Override
public void put(E e) throws InterruptedException {
this.blockingQueue.put(e);
}
#Override
public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
return this.blockingQueue.offer(e, timeout, unit);
}
#Override
public E take() throws InterruptedException {
return this.blockingQueue.take();
}
#Override
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
return this.blockingQueue.poll(timeout, unit);
}
#Override
public int remainingCapacity() {
return this.blockingQueue.remainingCapacity();
}
#Override
public boolean remove(Object o) {
return this.blockingQueue.remove(o);
}
#Override
public boolean contains(Object o) {
return this.blockingQueue.contains(o);
}
#Override
public int drainTo(Collection<? super E> c) {
return this.blockingQueue.drainTo(c);
}
#Override
public int drainTo(Collection<? super E> c, int maxElements) {
return this.blockingQueue.drainTo(c, maxElements);
}
}
RejectedExecutionHandlerImpl
package com.gunjan;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
public class RejectedExecutionHandlerImpl implements RejectedExecutionHandler {
#Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
boolean inserted = ((CustomBlockingQueue) executor.getQueue()).customOffer(r);
if (!inserted) {
throw new RejectedExecutionException();
}
}
}
CustomThreadPoolExecutorTest
package com.gunjan;
import java.util.concurrent.*;
public class CustomThreadPoolExecutorTest {
public static void main(String[] args) throws InterruptedException {
LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<Runnable>(500);
CustomBlockingQueue customLinkedBlockingQueue = new ThreadPoolBlockingQueue<Runnable>(linkedBlockingQueue);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 100, 60, TimeUnit.SECONDS,
customLinkedBlockingQueue, new RejectedExecutionHandlerImpl());
for (int i = 0; i < 750; i++) {
try {
threadPoolExecutor.submit(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(threadPoolExecutor);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
} catch (RejectedExecutionException e) {
e.printStackTrace();
}
}
threadPoolExecutor.shutdown();
threadPoolExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.MINUTES);
System.out.println(threadPoolExecutor);
}
}

Is there an ExecutorService that uses the current thread?

What I am after is a compatible way to configure the use of a thread pool or not. Ideally the rest of the code should not be impacted at all. I could use a thread pool with 1 thread but that isn't quite what I want. Any ideas?
ExecutorService es = threads == 0 ? new CurrentThreadExecutor() : Executors.newThreadPoolExecutor(threads);
// es.execute / es.submit / new ExecutorCompletionService(es) etc
Java 8 style:
Executor e = Runnable::run;
You can use Guava's MoreExecutors.newDirectExecutorService(), or MoreExecutors.directExecutor() if you don't need an ExecutorService.
If including Guava is too heavy-weight, you can implement something almost as good:
public final class SameThreadExecutorService extends ThreadPoolExecutor {
private final CountDownLatch signal = new CountDownLatch(1);
private SameThreadExecutorService() {
super(1, 1, 0, TimeUnit.DAYS, new SynchronousQueue<Runnable>(),
new ThreadPoolExecutor.CallerRunsPolicy());
}
#Override public void shutdown() {
super.shutdown();
signal.countDown();
}
public static ExecutorService getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
static ExecutorService instance = createInstance();
}
private static ExecutorService createInstance() {
final SameThreadExecutorService instance
= new SameThreadExecutorService();
// The executor has one worker thread. Give it a Runnable that waits
// until the executor service is shut down.
// All other submitted tasks will use the RejectedExecutionHandler
// which runs tasks using the caller's thread.
instance.submit(new Runnable() {
#Override public void run() {
boolean interrupted = false;
try {
while (true) {
try {
instance.signal.await();
break;
} catch (InterruptedException e) {
interrupted = true;
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}});
return Executors.unconfigurableScheduledExecutorService(instance);
}
}
Here's a really simple Executor (not ExecutorService, mind you) implementation that only uses the current thread. Stealing this from "Java Concurrency in Practice" (essential reading).
public class CurrentThreadExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
ExecutorService is a more elaborate interface, but could be handled with the same approach.
I wrote an ExecutorService based on the AbstractExecutorService.
/**
* Executes all submitted tasks directly in the same thread as the caller.
*/
public class SameThreadExecutorService extends AbstractExecutorService {
//volatile because can be viewed by other threads
private volatile boolean terminated;
#Override
public void shutdown() {
terminated = true;
}
#Override
public boolean isShutdown() {
return terminated;
}
#Override
public boolean isTerminated() {
return terminated;
}
#Override
public boolean awaitTermination(long theTimeout, TimeUnit theUnit) throws InterruptedException {
shutdown(); // TODO ok to call shutdown? what if the client never called shutdown???
return terminated;
}
#Override
public List<Runnable> shutdownNow() {
return Collections.emptyList();
}
#Override
public void execute(Runnable theCommand) {
theCommand.run();
}
}
I had to use the same "CurrentThreadExecutorService" for testing purposes and, although all suggested solutions were nice (particularly the one mentioning the Guava way), I came up with something similar to what Peter Lawrey suggested here.
As mentioned by Axelle Ziegler here, unfortunately Peter's solution won't actually work because of the check introduced in ThreadPoolExecutor on the maximumPoolSize constructor parameter (i.e. maximumPoolSize can't be <=0).
In order to circumvent that, I did the following:
private static ExecutorService currentThreadExecutorService() {
CallerRunsPolicy callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();
return new ThreadPoolExecutor(0, 1, 0L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), callerRunsPolicy) {
#Override
public void execute(Runnable command) {
callerRunsPolicy.rejectedExecution(command, this);
}
};
}
You can use the RejectedExecutionHandler to run the task in the current thread.
public static final ThreadPoolExecutor CURRENT_THREAD_EXECUTOR = new ThreadPoolExecutor(0, 0, 0, TimeUnit.DAYS, new SynchronousQueue<Runnable>(), new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
r.run();
}
});
You only need one of these ever.

How to use MDC with thread pools?

In our software we extensively use MDC to track things like session IDs and user names for web requests. This works fine while running in the original thread.
However, there's a lot of things that need to be processed in the background. For that we use the java.concurrent.ThreadPoolExecutor and java.util.Timer classes along with some self-rolled async execution services. All these services manage their own thread pool.
This is what Logback's manual has to say about using MDC in such an environment:
A copy of the mapped diagnostic context can not always be inherited by worker threads from the initiating thread. This is the case when java.util.concurrent.Executors is used for thread management. For instance, newCachedThreadPool method creates a ThreadPoolExecutor and like other thread pooling code, it has intricate thread creation logic.
In such cases, it is recommended that MDC.getCopyOfContextMap() is invoked on the original (master) thread before submitting a task to the executor. When the task runs, as its first action, it should invoke MDC.setContextMapValues() to associate the stored copy of the original MDC values with the new Executor managed thread.
This would be fine, but it is a very easy to forget adding those calls, and there is no easy way to recognize the problem until it is too late. The only sign with Log4j is that you get missing MDC info in the logs, and with Logback you get stale MDC info (since the thread in the tread pool inherits its MDC from the first task that was ran on it). Both are serious problems in a production system.
I don't see our situation special in any way, yet I could not find much about this problem on the web. Apparently, this is not something that many people bump up against, so there must be a way to avoid it. What are we doing wrong here?
Yes, this is a common problem I've run into as well. There are a few workarounds (like manually setting it, as described), but ideally you want a solution that
Sets the MDC consistently;
Avoids tacit bugs where the MDC is incorrect but you don't know it; and
Minimizes changes to how you use thread pools (e.g. subclassing Callable with MyCallable everywhere, or similar ugliness).
Here's a solution that I use that meets these three needs. Code should be self-explanatory.
(As a side note, this executor can be created and fed to Guava's MoreExecutors.listeningDecorator(), if
you use Guava's ListanableFuture.)
import org.slf4j.MDC;
import java.util.Map;
import java.util.concurrent.*;
/**
* A SLF4J MDC-compatible {#link ThreadPoolExecutor}.
* <p/>
* In general, MDC is used to store diagnostic information (e.g. a user's session id) in per-thread variables, to facilitate
* logging. However, although MDC data is passed to thread children, this doesn't work when threads are reused in a
* thread pool. This is a drop-in replacement for {#link ThreadPoolExecutor} sets MDC data before each task appropriately.
* <p/>
* Created by jlevy.
* Date: 6/14/13
*/
public class MdcThreadPoolExecutor extends ThreadPoolExecutor {
final private boolean useFixedContext;
final private Map<String, Object> fixedContext;
/**
* Pool where task threads take MDC from the submitting thread.
*/
public static MdcThreadPoolExecutor newWithInheritedMdc(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue) {
return new MdcThreadPoolExecutor(null, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
/**
* Pool where task threads take fixed MDC from the thread that creates the pool.
*/
#SuppressWarnings("unchecked")
public static MdcThreadPoolExecutor newWithCurrentMdc(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue) {
return new MdcThreadPoolExecutor(MDC.getCopyOfContextMap(), corePoolSize, maximumPoolSize, keepAliveTime, unit,
workQueue);
}
/**
* Pool where task threads always have a specified, fixed MDC.
*/
public static MdcThreadPoolExecutor newWithFixedMdc(Map<String, Object> fixedContext, int corePoolSize,
int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
return new MdcThreadPoolExecutor(fixedContext, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
private MdcThreadPoolExecutor(Map<String, Object> fixedContext, int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
this.fixedContext = fixedContext;
useFixedContext = (fixedContext != null);
}
#SuppressWarnings("unchecked")
private Map<String, Object> getContextForTask() {
return useFixedContext ? fixedContext : MDC.getCopyOfContextMap();
}
/**
* All executions will have MDC injected. {#code ThreadPoolExecutor}'s submission methods ({#code submit()} etc.)
* all delegate to this.
*/
#Override
public void execute(Runnable command) {
super.execute(wrap(command, getContextForTask()));
}
public static Runnable wrap(final Runnable runnable, final Map<String, Object> context) {
return new Runnable() {
#Override
public void run() {
Map previous = MDC.getCopyOfContextMap();
if (context == null) {
MDC.clear();
} else {
MDC.setContextMap(context);
}
try {
runnable.run();
} finally {
if (previous == null) {
MDC.clear();
} else {
MDC.setContextMap(previous);
}
}
}
};
}
}
We have run into a similar problem. You might want to extend ThreadPoolExecutor and override before/afterExecute methods to make the MDC calls you need before starting/stopping new threads.
IMHO the best solution is to:
use ThreadPoolTaskExecutor
implement your own TaskDecorator
use it: executor.setTaskDecorator(new LoggingTaskDecorator());
The decorator can look like this:
private final class LoggingTaskDecorator implements TaskDecorator {
#Override
public Runnable decorate(Runnable task) {
// web thread
Map<String, String> webThreadContext = MDC.getCopyOfContextMap();
return () -> {
// work thread
try {
// TODO: is this thread safe?
MDC.setContextMap(webThreadContext);
task.run();
} finally {
MDC.clear();
}
};
}
}
This is how I do it with fixed thread pools and executors:
ExecutorService executor = Executors.newFixedThreadPool(4);
Map<String, String> mdcContextMap = MDC.getCopyOfContextMap();
In the threading part:
executor.submit(() -> {
MDC.setContextMap(mdcContextMap);
// my stuff
});
In case you face this problem in a spring framework related environment where you run tasks by using #Async annotation you are able to decorate the tasks by using the TaskDecorator approach.
A sample of how to do it is provided here:
Spring 4.3: Using a TaskDecorator to copy MDC data to #Async
threads
I faced this issue and the article above helped me to tackle it so that's why I am sharing it here.
Similar to the previously posted solutions, the newTaskFor methods for Runnable and Callable can be overwritten in order to wrap the argument (see accepted solution) when creating the RunnableFuture.
Note: Consequently, the executorService's submit method must be called instead of the execute method.
For the ScheduledThreadPoolExecutor, the decorateTask methods would be overwritten instead.
Another variation similar to existing answers here is to implement ExecutorService and allow a delegate to be passed to it. Then using generics, it can still expose the actual delegate in case one wants to get some stats (as long no other modification methods are used).
Reference code:
https://github.com/project-ncl/pnc/blob/master/common/src/main/java/org/jboss/pnc/common/concurrent/MDCThreadPoolExecutor.java
https://github.com/project-ncl/pnc/blob/master/common/src/main/java/org/jboss/pnc/common/concurrent/MDCWrappers.java
public class MDCExecutorService<D extends ExecutorService> implements ExecutorService {
private final D delegate;
public MDCExecutorService(D delegate) {
this.delegate = delegate;
}
#Override
public void shutdown() {
delegate.shutdown();
}
#Override
public List<Runnable> shutdownNow() {
return delegate.shutdownNow();
}
#Override
public boolean isShutdown() {
return delegate.isShutdown();
}
#Override
public boolean isTerminated() {
return delegate.isTerminated();
}
#Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return delegate.awaitTermination(timeout, unit);
}
#Override
public <T> Future<T> submit(Callable<T> task) {
return delegate.submit(wrap(task));
}
#Override
public <T> Future<T> submit(Runnable task, T result) {
return delegate.submit(wrap(task), result);
}
#Override
public Future<?> submit(Runnable task) {
return delegate.submit(wrap(task));
}
#Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
return delegate.invokeAll(wrapCollection(tasks));
}
#Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException {
return delegate.invokeAll(wrapCollection(tasks), timeout, unit);
}
#Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
return delegate.invokeAny(wrapCollection(tasks));
}
#Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return delegate.invokeAny(wrapCollection(tasks), timeout, unit);
}
#Override
public void execute(Runnable command) {
delegate.execute(wrap(command));
}
public D getDelegate() {
return delegate;
}
/* Copied from https://github.com/project-ncl/pnc/blob/master/common/src/main/java/org/jboss/pnc/common
/concurrent/MDCWrappers.java */
private static Runnable wrap(final Runnable runnable) {
final Map<String, String> context = MDC.getCopyOfContextMap();
return () -> {
Map previous = MDC.getCopyOfContextMap();
if (context == null) {
MDC.clear();
} else {
MDC.setContextMap(context);
}
try {
runnable.run();
} finally {
if (previous == null) {
MDC.clear();
} else {
MDC.setContextMap(previous);
}
}
};
}
private static <T> Callable<T> wrap(final Callable<T> callable) {
final Map<String, String> context = MDC.getCopyOfContextMap();
return () -> {
Map previous = MDC.getCopyOfContextMap();
if (context == null) {
MDC.clear();
} else {
MDC.setContextMap(context);
}
try {
return callable.call();
} finally {
if (previous == null) {
MDC.clear();
} else {
MDC.setContextMap(previous);
}
}
};
}
private static <T> Consumer<T> wrap(final Consumer<T> consumer) {
final Map<String, String> context = MDC.getCopyOfContextMap();
return (t) -> {
Map previous = MDC.getCopyOfContextMap();
if (context == null) {
MDC.clear();
} else {
MDC.setContextMap(context);
}
try {
consumer.accept(t);
} finally {
if (previous == null) {
MDC.clear();
} else {
MDC.setContextMap(previous);
}
}
};
}
private static <T> Collection<Callable<T>> wrapCollection(Collection<? extends Callable<T>> tasks) {
Collection<Callable<T>> wrapped = new ArrayList<>();
for (Callable<T> task : tasks) {
wrapped.add(wrap(task));
}
return wrapped;
}
}

Submitting FutureTasks to an Executor - why does it work?

I have the following test code.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
class MyTask extends FutureTask<String>{
#Override
protected void done() {
System.out.println("Done");
}
public MyTask(Runnable runnable) {
super(runnable,null);
}
}
public class FutureTaskTest {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
FutureTask<String> future = new MyTask(new Runnable() {
public void run() {
System.out.println("Running");
}
});
executor.submit(future);
try {
future.get();
} catch (Exception ex ) {
ex.printStackTrace();
}
executor.shutdownNow();
}
}
This works fine - the overridden 'done' methond in MyTask is called when the task is done.
But how does the executor know how to call that ?
The executor only have these submit methods:
public <T> Future<T> submit(Callable<T> task);
public Future<?> submit(Runnable task);
Internally it seems 'submit' wraps the callable/runnable in a new FutureTask().
As far as the executor is concerned I've submitted a Runnable or Callable - from what I gather from these 2 signatures.
How does it know I submitted a FutureTask and know how to call my overridden done() ?
From the executor's point of view, you've submitted a Runnable task. The run method of this task (implemented by FutureTask) is what calls done at the appropriate time. The executor doesn't make any direct call to done.
The executor doesn't call done(). done() gets called by FutureTask when the call to run() is complete.

Categories