28

Future.get(timeout) は、指定されたタイムアウト後に TimeoutException を確実にスローしません。これは正常な動作ですか、それとも信頼性を高めるために何かできることはありますか? このテストは私のマシンでは失敗します。ただし、2000 ではなく 3000 でスリープすると合格します。

public class FutureTimeoutTest {
@Test
public void test() throws
    ExecutionException,
    InterruptedException {

    ExecutorService exec = Executors.newSingleThreadExecutor();
    final Callable call = new Callable() {
        @Override
        public Object call() throws Exception {
             try {
                Thread.sleep(2000);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            return 0;
        }
    };
    final Future future = exec.submit(call);
    try {
        future.get(1000, TimeUnit.MILLISECONDS);
        fail("expected TimeoutException");
    } catch (TimeoutException ignore) {
    }
}

}

4

3 に答える 3

15

テストに合格することを期待する理由はありません。実行のためにタスクを送信し、その完了を待機すると、待機が始まる前に任意の時間が経過する可能性がFuture#get()あり、タスクがスリープ期間を使い果たして完了するのに十分な時間が与えられます。

あなたの場合、実行可能な状態にあるにもかかわらず、Executor実行中のメインスレッドが保留されている間、内で実行中のスレッドがフォーカスを取得すると想定できます。test()サブミットされたタスクを 2 秒と 3 秒間ストールさせた場合の違いについては、コンピューターで他のプロセスが忙しくしていることに応じて、3 秒でも不十分な状況を見つけることができると思います。

于 2010-12-04T00:48:05.030 に答える
10

@sehは正しいです。

一般に Java の「リアルタイム」動作と呼ばれるものを期待しています。これは、リアルタイム オペレーティング システム上で実行されているリアルタイム対応の Java ディストリビューションでリアルタイム ライブラリを使用しない限り、確実に実現することはできません。

たとえば、HotSpot などの最新の JVM での Java スレッドの実装は、ホスト オペレーティング システムのネイティブ スレッド スケジューラに依存して、どのスレッドをいつ実行するかを決定します。スレッド スケジューラがリアルタイムのデッドラインなどを明確に認識していない限り、どのスレッドをいつ実行するかを決定する際に、「システム全体」のビューを使用する可能性があります。システムがロードされている場合、特定のスレッドは、実行を妨げていた条件 (タイマー イベントの待機など) が経過した後、数秒間またはそれ以上実行するようにスケジュールされない場合があります。

次に、Java GC によって他のすべてのスレッドがブロックされる可能性があるという問題があります。

Java からのリアルタイム動作が本当に必要な場合は、利用できます。例えば:

ただし、アプリケーションを変更して別の API を使用し、リアルタイムの動作を提供することを想定する必要があります。

于 2010-12-04T01:18:29.940 に答える
9

私が言わなければならないのは、現在、他の 2 つの回答は、Java 同時実行クラスについて不必要に低い意見を持っていると思います。ミリ秒単位の精度 (「リアルな」リアルタイム アプリケーションが期待する精度) は得られませんが、通常は非常にうまく機能します。Futures と Executor を使用して大規模な商用サービスを作成しましたが、負荷がかかっていても、通常は予想時間の 10 ミリ秒以内に動作しました。

Java 1.6 を搭載した MacOS 10.6 と Java 1.6.0_22 を搭載した WinXP の両方でこのテストを実行しましたが、どちらも期待どおりに動作します。

精度をテストするために、次のようにコードを変更しました。

    long time1 = System.nanoTime();

    System.out.println("Submitting");
    final Future<Object> future = exec.submit(call);
    try {
        future.get(1000, TimeUnit.MILLISECONDS);

        long time2 = System.nanoTime();
        System.out.println("No timeout after " + 
                             (time2-time1)/1000000000.0 + " seconds");

        fail("expected TimeoutException");
    } catch (TimeoutException ignore) {
        long time2 = System.nanoTime();
        System.out.println("Timed out after " +
                             (time2-time1)/1000000000.0 + " seconds");
    }
    finally {
        exec.shutdown();
    }

XPでは、これは「1.002598934秒後にタイムアウトしました」と出力し、MacOS Xでは「1.003158秒後にタイムアウトしました」と出力します。

元の投稿者が OS と JDK のバージョンを説明していれば、これが特定のバグであるかどうかを判断できる可能性があります。

于 2010-12-04T02:01:32.787 に答える