Java 如何进入未来任务执行状态?

Java 如何进入未来任务执行状态?,java,multithreading,futuretask,executors,Java,Multithreading,Futuretask,Executors,我有一个singleThreadExecutor,以串行顺序执行我提交给它的任务,即一个任务接一个任务,没有并行执行 我有类似这样的runnable MyRunnable implements Runnable { @Override public void run() { try { Thread.sleep(30000); } catch (InterruptedException e1) { e1.printStackTrace();

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

我有类似这样的runnable

MyRunnable implements Runnable {

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

例如,当我将MyRunnable的三个实例提交给上述单线程执行器时,我希望执行第一个任务,因为thread.sleep的执行线程处于TIMED_等待状态(我可能对特定状态有错误)。其他两个任务不应该分配线程来执行它们,至少在第一个任务完成之前是这样

因此,我的问题是如何通过FutureTask API获取该状态,或者以某种方式获取正在执行任务的线程(如果没有这样的线程,那么该任务正在等待执行或挂起)并获取其状态,或者通过其他方式获取其状态


FutureTask仅定义isCanceled()和isDone()方法,但这些方法不足以描述任务的所有可能执行状态

您可以将提交给此服务的任何内容包装在一个
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;
    }
}

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

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

在执行
try
块之前执行此操作:

myThread = Thread.currentThread();
然后添加一个
最后
块:

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
。您可以通过为状态转换设置一个
锁定
对象,并在更改一个或两个状态变量时对其进行同步来缓解此问题):


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

如果您想真正彻底执行,
FutureTask
会跟踪状态
READY
运行
运行
,以及
内部取消
。您可以创建此类的副本,并为状态添加访问器。然后重写
AbstractExecutorService.newTaskFor(Runnable)
,使用
CustomFutureTask
对其进行包装(内部类是
private
,因此仅子类化不起作用)

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

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}
protectedrunnablefuture newTaskFor(Runnable Runnable,T值){
返回新的FutureTask(可运行,值);
}

所以覆盖它并不是什么大问题。

因为FutureTask需要一个可调用对象,所以我们将创建一个简单的可调用实现

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

    }
import java.util.concurrent.Callable;
公共类MyCallable实现了Callable{
私人长时间等待;
公共MyCallable(int timeInMillis){
this.waitTime=timeInMillis;
}
@凌驾
公共字符串调用()引发异常{
睡眠(等待时间);
//返回执行此可调用任务的线程名称
返回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
            }
        }

    }
}
import java.util.concurrent.ExecutionException;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.FutureTask;
导入java.util.concurrent.TimeUnit;
导入java.util.concurrent.TimeoutException;
公共类未来任务示例{
公共静态void main(字符串[]args){
MyCallable callable1=新的MyCallable(1000);
MyCallable callable2=新的MyCallable(2000);
FutureTask futureTask1=新的FutureTask(callable1);
FutureTask futureTask2=新的FutureTask(callable2);
ExecutorService executor=Executors.newFixedThreadPool(2);
执行人。执行(未来任务1);
执行人。执行(未来任务2);
while(true){
试一试{
if(futureTask1.isDone()&futureTask2.isDone()){
系统输出打印项次(“完成”);
//关闭执行器服务
executor.shutdown();
返回;
}
如果(!futureTask1.isDone()){
//无限期等待将来的任务完成
System.out.println(“FutureTask1输出=“+FutureTask1.get());
}
System.out.println(“等待未来任务2完成”);
字符串s=futureTask2.get(200L,时间单位为毫秒);
如果(s!=null){
System.out.println(“FutureTask2输出=”+s);
}
}捕获(中断异常|执行异常e){
e、 printStackTrace();
}捕获(超时异常e){
//无所事事
}
}
}
}

与运行任何并发结果一样
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();
        }

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

    }
}