5

送信したタスクをシリアル順に実行するために、singleThreadExecutor があります。つまり、タスクを 1 つずつ実行し、並列実行しません。

私はこのようなものになるrunnableを持っています

MyRunnable implements Runnable {

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

}

たとえば、MyRunnable の 3 つのインスタンスを前述のシングル スレッド エグゼキュータに送信すると、最初のタスクが実行されると予想されます。Thread.sleep には実行中のスレッドが TIMED_WAITING にあるためです (具体的には間違っている可能性があります)。州)。他の 2 つのタスクには、少なくとも最初のタスクが終了するまで、それらを実行するためのスレッドを割り当てないでください。

したがって、私の質問は、FutureTask API を介してこの状態を取得する方法、または何らかの方法でタスクを実行しているスレッドに到達する方法です (そのようなスレッドがない場合、タスクは実行または保留中を待機しています)。他の意味?

FutureTask は isCanceled() および isDone() メソッドのみを定義していますが、それらは Task の考えられるすべての実行ステータスを説明するには十分ではありません。

4

4 に答える 4

3

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

メソッドを実行するメソッドgetThread()を追加することができます。MyRunnableThreadrun()

このようなインスタンス変数を追加することをお勧めします(正確さを確保するために揮発性である必要があります):

 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、1つの状態をキャプチャする2つの値があるため、競合状態が少しあります。特に、このアプローチでは、とを観察できますisDone() == truegetThread() != null軽減できます。これは、lock状態遷移のオブジェクトを持ち、一方または両方の状態変数を変更するときにそのオブジェクトで同期することによって):

done = true;

MyRunnable1つを2つ以上のスレッドに同時に送信することを禁止するガードはまだないことに注意してください。私はあなたがこれをしていないとあなたが言うことを知っています...今日:)複数の同時実行は高い可能性で破損した状態につながるでしょう。runメソッドの先頭に相互に排他的なガード(メソッドsynchronizedへの書き込みなど)を配置して、常に1回の実行のみが行われるようにすることができます。run()

于 2011-08-03T21:08:00.607 に答える
1

本当に徹底したい場合は、、 、、および内部FutureTaskの状態を追跡します。このクラスのコピーを作成し、状態のアクセサーを追加できます。次に、あなたを使用してそれをラップするようにオーバーライドします(内部クラスはであるため、サブクラス化だけでは機能しません)。READYRUNNINGRANCANCELLEDAbstractExecutorService.newTaskFor(Runnable)CustomFutureTaskprivate

のデフォルトの実装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 には呼び出し可能なオブジェクトが必要なので、単純な Cal​​lable 実装を作成します。

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 に答える