How to get to FutureTask execution state?
You could wrap anything you submit to this service in a Runnable
that records when its run method is entered.
public class RecordingRunnable implements Runnable { private final Runnable actualTask; private volatile boolean isRunning = false; //constructor, etc public void run() { isRunning = true; actualTask.run(); isRunning = false; } public boolean isRunning() { return isRunning; }}
You could add a getThread()
method to MyRunnable
that produces the Thread
executing the run()
method.
I would suggest adding an instance variable like this (must be volatile to ensure correctness):
private volatile Thread myThread;
Do this before the try
block:
myThread = Thread.currentThread();
And add a finally
block with this:
myThread = null;
Then you could call:
final Thread theThread = myRunnable.getThread();if (theThread != null) { System.out.println(theThread.getState());}
for some MyRunnable
.
null
is an ambiguous result at this point, meaning either, "hasn't run," or "has completed." Simply add a method that tells whether the operation has completed:
public boolean isDone() { return done;}
Of course, you'll need an instance variable to record this state:
private volatile boolean done;
And set it to true in the finally
block (probably before setting the thread to null
, there's a bit of a race condition there because there are two values capturing the state of one thing. In particular, with this approach you could observe isDone() == true
and getThread() != null
. You could mitigate this by having a lock
object for state transitions and synchronize on it when changing one or both state variables):
done = true;
Note that there still isn't any guard that prohibits a single MyRunnable
from being submitted concurrently to two or more threads. I know you say that you're not doing this... today :) Multiple concurrent executions will lead to corrupted state with high likelihood. You could put some mutual exclusive guard (such as simply writing synchronized
on the run()
method) at the beginning of the run method to ensure that only a single execution is happening at any given time.
If you wanted to be really thorough, FutureTask
keeps track of states READY
, RUNNING
, RAN
, and CANCELLED
internally. You could create a copy of this class and add an accessor for the state. Then override AbstractExecutorService.newTaskFor(Runnable)
to wrap it using your CustomFutureTask
(the inner class is private
, so just subclassing won't work).
The default implementation of newTaskFor(Runnable)
is really simple:
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value);}
so it wouldn't be a big deal to override it.