开发者

How to get to FutureTask execution state?

I have a singleThreadExecutor in order to execute the tasks I submit to it in serial order i.e. one task after another, no parallel execution.

I have runnable which goes something like this

MyRunnable implements Runnable {

@Override
public void run() {
    try {
        Thread.sleep(30000);
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }

}

When I submit ,for example, three instances of MyRunnable to the afore-mentioned single thread executor, I would expect to have the first task executing and because of the Thread.sleep has Its executing thread in TIMED_WAITING (I may be wrong about the specific state). The other two tasks should not have thr开发者_运维百科eads assigned to execute them, at least not until the first task has finished.

So my question is how to get this state via the FutureTask API or somehow get to the thread that is executing the task (if there is no such thread then the task is waiting to be executed or pending) and get Its state or perhaps by some other means?

FutureTask only defines isCanceled() and isDone() methods, but those are not quite enough to describe all the possible execution statuses of the Task.


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.


Since FutureTask requires a callable object, we will create a simple Callable implementation.

import java.util.concurrent.Callable;

    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();
        }

    }

Here is an example of FutureTask method and it’s showing commonly used methods of FutureTask.

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
            }
        }

    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜