如何进入FutureTask执行状态?

我有一个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的所有可能的执行状态。

您可以将一个getThread()方法添加到MyRunnable ,以生成执行run()方法的Thread

我建议添加一个这样的实例变量(必须是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; 

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

 done = true; 

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

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

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

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

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

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

所以覆盖它并不是什么大不了的事。

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

 import java.util.concurrent.Callable; public class MyCallable implements Callable { 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 futureTask1 = new FutureTask(callable1); FutureTask futureTask2 = new FutureTask(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 } } } }