0

特定の時間スレッドを実行し、時間が経過したときに何らかの結果を返すにはどうすればよいですか?

これまで考えられる最善の解決策は、時間を手動で測定することです。しかし、もっとエレガントな、すぐに使えるソリューションがあるのではないでしょうか。 

各反復で以前のソリューションを改善するアルゴリズムがあります。このコードを別のスレッドで事前定義された時間実行したいと思います。時間が経過すると、最良の(最新の)ソリューションが返されます。

ソリューションを返したいので、単に使用することはできませんFuture#get(long timeout, TimeUnit unit)-結果としてTimeoutException。「制御」スレッドからしばらくしてからスレッドを中断する場合も同じです。このような場合、Futureキャンセルされて返されnullます。

私の現在の解決策は次のとおりです。

タイマーロジック:

private class ExecutionTimer {

    private final long executionTimeLimit;

    private long startTime;

    // accepts execution time limit in _miliseconds_
    public ExecutionTimer(final int executionTimeLimit) {
        this.executionTimeLimit = TimeUnit.MILLISECONDS.toNanos(executionTimeLimit);
    }

    public void start() {
        this.startTime = System.nanoTime();
    }

    public boolean hasElapsed() {
        return (System.nanoTime() - startTime) >= executionTimeLimit;
    }
}

...そしてワーカースレッド:

 private class WorkerThread implements Callable<Double> {

        private final ExecutionTimer executionTimer;

        public WorkerThread(final int executionTimeLimit) {
            this.executionTimer = new ExecutionTimer(executionTimeLimit);
        }

        @Override
        public Double call() throws Exception {
            executionTimer.start();

            double partialSolution = 0;
            while (!executionTimer.hasElapsed()) {
                // let's imagine that here solution is improved ;)
                partialSolution = new Random().nextDouble(); 
            }
            return partialSolution;
        }
    }

編集: ワーカースレッドは、外部から中断することなく無期限に動作できます-アルゴリズムは常に以前のソリューションを改善できるため、問題ありません(もちろん、かなりの時間が経過した後の改善は比較的小さいです)

4

4 に答える 4

2

中間結果を共有スレッドセーフ変数に格納できます(たとえばvolatile double、あなたの場合)-将来タイムアウトになったときに、その変数から最新の計算値を取得できます。

言い換えると:

  • future.get(...)値を返す場合は、それを使用します
  • を取得した場合はTimeoutException、を呼び出して値を取得します。これにより、ローカルのではなく、ループごとに更新されるがyourWorkerThread.getLatestValue();返されます。volatile double latestValuepartialSolution

あるいは、この投稿はGuavaライブラリと他のソリューションを指しています(これらはすべて、私のコメントで説明した2つのオプションに帰着します)。Guavaは、内部的に、タイムアウト付きのfutureを使用することに注意してください。

于 2012-08-18T17:56:12.457 に答える
1

私は生産者/消費者パターンを提案します:

結果の育成を担当するアルゴリズムは、常に新しくより良い結果を生成し、それらを共有スレッドセーフリソースに配置します。

この結果に関心のあるクライアントは、質問のタイムアウトに設定された、事前定義された間隔ごとにこのリソースを消費します。

リソース自体は、ストリーム(BlockingQueueなど)または単一の変数である可能性があります。

これには、推論が非常に簡単で、明確な境界を定義し、非常に柔軟であるという利点があります。例:クライアントは、結果がまったくない限りブロックできます。または、新しく改善された結果がない限りブロックできます。生産者/消費者パターンのすべてのバリエーションは、生産者通知条件を微調整するだけです。

于 2012-08-18T19:18:55.943 に答える
1

TimerTimerTaskの使用を検討してください

import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;

public class Solver implements Callable<Double> {

    private final AtomicBoolean running = new AtomicBoolean(true);

    public void stop() {
        this.running.set(true);
    }

    @Override
    public Double call() throws Exception {
        Double answer = null;
        while (this.running.get()) {
            answer = keepImproving();
        }
        // TODO Auto-generated method stub
        return answer;
    }

}

class Schedular extends TimerTask {

    private final Solver solver;

    public Schedular(Solver solver) {
        this.solver = solver;
    }

    @Override
    public void run() {
        this.solver.stop();
    }

}

以下のようなものを使用してください

final Solver solver = new Solver();
Schedular schedular = new Schedular(solver);
final Timer timer = new Timer();
timer.schedule(schedular, 0, TimeUnit.MINUTES.toMillis(1));

ExecutorService executor = // get a executor somehow
final Future<Double> future = executor.submit(solver);
final Double answer = future.get();
System.out.println(answer);

アイデアは、Timer&を使用TimerTaskして停止信号をトリガーし、アルゴリズムが回答の改善を停止するようにすることです。

于 2012-08-18T19:35:06.853 に答える
0

通常のFuture.get()を使用でき、無期限に待機します。

于 2012-08-18T17:57:58.243 に答える