[英]How to get to FutureTask execution state?
我有一个singleThreadExecutor以便以串行顺序执行提交给它的任务,即一个任务接一个,没有并行执行。
我有可运行的东西,像这样
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的所有可能执行状态。
您可以将提交给该服务的所有内容包装到一个Runnable
,该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;
}
}
您可以在MyRunnable
中添加一个getThread()
方法,该方法将生成执行run()
方法的Thread
。
我建议添加一个这样的实例变量(必须可变以确保正确性):
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() == true
和getThread() != null
,您可以通过添加一个用于状态转换的lock
对象来缓解这种情况,并在更改一个或两个状态变量时对其进行同步):
done = true;
请注意,仍然没有任何防护措施禁止将单个MyRunnable
同时提交给两个或多个线程。 我知道您说您今天不这样做... :)多个并发执行极有可能导致损坏状态。 您可以在run()
方法的开头放置一些互斥防护(例如,简单地在run()
方法上synchronized
编写),以确保在任何给定时间仅发生一次执行。
如果您想真正做到透彻, FutureTask
会在内部跟踪状态READY
, RUNNING
, RAN
和CANCELLED
。 您可以创建此类的副本并为该状态添加访问器。 然后重写AbstractExecutorService.newTaskFor(Runnable)
以使用您的CustomFutureTask
对其进行包装(内部类是private
,因此子类将无法工作)。
newTaskFor(Runnable)
的默认实现非常简单:
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
因此覆盖它并没什么大不了的。
由于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
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.