5

我有一个singleThreadExecutor,以便按顺序执行我提交给它的任务,即一个接一个的任务,没有并行执行。

我有 runnable 是这样的

MyRunnable implements Runnable {

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

}

例如,当我将 MyRunnable 的三个实例提交给上述单线程执行器时,我希望第一个任务正在执行,并且由于 Thread.sleep 在 TIMED_WAITING 中有其执行线程(我可能对具体的错误状态)。其他两个任务不应该分配线程来执行它们,至少在第一个任务完成之前是这样。

所以我的问题是如何通过 FutureTask API 获得这种状态,或者以某种方式到达正在执行任务的线程(如果没有这样的线程,那么任务正在等待执行或挂起)并获得它的状态,或者可能通过一些其他手段?

FutureTask 只定义了 isCanceled() 和 isDone() 方法,但不足以描述 Task 的所有可能执行状态。

4

4 回答 4

3

您可以将您提交给此服务的任何内容包装在Runnable输入其运行方法时的记录中。

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;
    }
}
于 2011-08-03T21:01:46.953 回答
2

您可以添加一个getThread()方法来MyRunnable生成Thread执行该run()方法。

我建议添加这样的实例变量(必须是volatile以确保正确性):

 private volatile Thread myThread;

try在块之前执行此操作:

myThread = Thread.currentThread();

并用这个添加一个finally块:

myThread = null;

然后你可以打电话:

final Thread theThread = myRunnable.getThread();
if (theThread != null) {
    System.out.println(theThread.getState());
}

对于一些MyRunnable.

null在这一点上是一个模棱两可的结果,意思是“尚未运行”或“已完成”。只需添加一个告诉操作是否已完成的方法:

public boolean isDone() {
    return done;
}

当然,您需要一个实例变量来记录此状态:

private volatile boolean done;

并在块中将其设置为 true finally(可能在将线程设置为 之前null,存在一些竞争条件,因为有两个值捕获一件事的状态。特别是,通过这种方法,您可以观察到isDone() == truegetThread() != null。您可以减轻这通过拥有一个lock用于状态转换的对象并在更改一个或两个状态变量时对其进行同步):

done = true;

请注意,仍然没有任何防护措施禁止将单个MyRunnable线程同时提交给两个或多个线程。我知道你说你今天没有这样做...... :) 多个并发执行很可能会导致损坏状态。您可以在 run 方法的开头放置一些互斥保护(例如简单地写synchronizedrun()方法上),以确保在任何给定时间只发生一次执行。

于 2011-08-03T21:08:00.607 回答
1

如果您想真正彻底,请FutureTask跟踪状态READYRUNNINGRANCANCELLED内部。您可以创建此类的副本并为状态添加访问器。然后使用你的重写AbstractExecutorService.newTaskFor(Runnable)来包装它CustomFutureTask(内部类是private,所以只是子类化不起作用)。

的默认实现newTaskFor(Runnable)非常简单:

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

所以覆盖它不会有什么大不了的。

于 2012-09-14T20:14:38.927 回答
0

由于 FutureTask 需要一个可调用对象,我们将创建一个简单的 Callable 实现。

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

    }

这是 FutureTask 方法的示例,它显示了 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
            }
        }

    }
}
于 2014-07-25T06:48:45.837 回答