2011-08-03 14 views
5

私は、タスクを実行するためにsingleThreadExecutorを持っています。つまり、並行して実行されないタスクが1つずつ順番に実行されます。以下のようなものだFutureTaskの実行状態を取得する方法は?

私が実行可能にしていこの

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()メソッドのみを定義しますが、タスクの実行可能な状態をすべて説明するには十分ではありません。

+2

質問はなぜisDone()以外に必要なのですか? – bestsss

答えて

2

あなたはrun()メソッドを実行Threadを生成MyRunnableからgetThread()メソッドを追加することができます。

私は(正確さを保証するために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は、この時点で曖昧な結果であり、「実行されていません」または「完了しました」を意味します。単に操作が完了したかどうかを伝える方法を追加:

private volatile boolean done; 

そしてfinallyブロックでtrueに設定:もちろん

public boolean isDone() { 
    return done; 
} 

を、あなたはこの状態を記録するために、インスタンス変数が必要になります(おそらくスレッドをnullに設定する前に、1つのものの状態をキャプチャする2つの値があるため、少し競合状態があります。特に、この方法ではisDone() == truegetThread() != nullを観察できます。あなたは)状態遷移のためのlockオブジェクトを持つことでこれを緩和し、一方または両方の状態変数を変更するとき、それに同期させることができます:

done = true; 

注まだ同時に提出されることから、単一のMyRunnableを禁止しているいずれかのガードがないこと2つ以上のスレッドに割り当てます。私はあなたがこれをやっていないと言うことを知っている...今日:)複数の同時実行は、高い確率で破損状態につながる。 runメソッドの開始時にいくつかの相互排他的なガード(例えば、run()メソッドに​​を書き込むなど)を実行して、特定の時点でただ1つの実行が確実に行われるようにすることができます。あなたが本当に徹底的になりたい場合は

+0

私はこのアプローチがThread.currentThread holdingフィールドで好きです。しかし、状態の完全なセットをカバーするために、これとMark Petersのソリューションの組み合わせが必要です。与えられた実行可能ファイルに割り当てられたcurrentThreadがない場合、これは実行可能ファイルがまだ実行中であるか、すでに実行されていることを意味する可能性があるため、例えばhasFinishedExecutionのような追加のフラグが必要です。とにかく、スレッドの状態は実行可能ファイルの実際の実行状態をよりネイティブに反映するため、これを「受け入れられた応答」とマークします。 – Svilen

+0

が更新されました。 –

+0

素晴らしい!包括的な例をありがとう。 – Svilen

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

isRunning()は、それが有効なデータ競合であることを確認するので、実際の意味はありません。 'java.util.concurrent.Future'は、' false-true-false'をフリップフロップしないで 'true'を残した' isDone() 'を持っています。 – bestsss

+1

@best: 'hasStarted'のようなブール値を簡単に使うことができ、runメソッドが入力されたときだけ記録するか、すべての状態をカバーする' enum'を使うことができます。この例は、ラッパー概念のデモンストレーションのためのものです。 –

1

は、FutureTaskは内部状態READYRUNNINGRAN、およびCANCELLEDを追跡します。このクラスのコピーを作成し、状態のアクセサを追加することができます。次にAbstractExecutorService.newTaskFor(Runnable)をオーバーライドしてCustomFutureTaskを使用してラップします(内部クラスはprivateなので、サブクラス化は機能しません)。

newTaskFor(Runnable)のデフォルトの実装は本当に簡単です:

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

ので、それをオーバーライドする大したことではないでしょう。

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

    } 
} 
関連する問題