3

これが私がやりたいことです。与えられた関数

public void foo() {

}

一定時間経過したら終了させたいです。つまり、これがある種の乱数発生器であり、いくつかの困難な制約を満たすランダム オブジェクトを生成する必要があると想像してください。つまり、関数は実際には次のようなものかもしれません

public void foo() {
   //task1
   while(fails) {
     //...
   }

   //task2
   while(fails2) {
      //...
   }

   //more tasks may follow, which use the data from the previous tasks to further try to satisfy difficult conditions
}

それはほんの一例です。しかし重要なのは、関数が多くの while ループ、多くのテスト ケース、および大量の計算で構成されていることです。

目標:「foo() を実行し、4 秒経過しても foo() がまだ完了していない場合は、すぐに foo() を停止する」と言えるようにしたいと考えています。

私が試したこと: foo() のほぼすべての行に条件を含めて、経過時間を確認し、4 秒が経過した場合に関数から戻るようにしました。しかし、 foo() がいかに複雑であるかを考えると、関数のすべての行で時間をテストする必要があるため、これをコード的に行うのは明らかに非常に困難です。

私の思考ロジック: System.exit(1) のように、状態に関係なくコードを終了する、この種のことを行う関数があるため、これは可能であると思います。それがアイデアです。この関数 foo() を終了させるために、外部から呼び出すことができるようにしたいと思います。

4

4 に答える 4

5
// foo method and global variables used
private static ArrayList<Integer> foo() {
    // info class
    class Info {
        public boolean run, completed;
        public ArrayList<Integer> list;
    }
    // declare info object, list
    final Info info = new Info();
    final Object wait = new Object();
    // run a new thread
    Thread t = new Thread(
        new Runnable() {
            // run method
            @Override
            public void run() {
                // setup run
                info.run = true;
                info.completed = false;
                info.list = new ArrayList<>();
                // loop to modify list. Don't put a big piece of code that will
                // take a long time to execute in here. 
                while(info.run) {
                    // example of what you should be doing in here:
                    info.list.add(1);
                    // and if you are done modifying the list, use:
                    break;
                }
                // done modifying list
                info.completed = true;
                synchronized(wait) {
                    wait.notify();
                }
            }
        }
    );
    t.start();
    // wait for four seconds, then return list
    try {
        synchronized(wait) {
            wait.wait(4000);
        }
    } catch (InterruptedException e) { e.printStackTrace(); }
    info.run = false;
    return info.completed ? info.list : null;
}
// main method
public static void main(String[] args) {
    // get list
    ArrayList<Integer> list = foo();
    System.out.println("Done!");
}

foo() メソッドは何をしますか?

  1. 最終的に返されるリストの変更を開始します
  2. このリストの変更にかかった時間が 4 秒を超えると、リストの変更が停止され、リストが返されます。
  3. リストが早期に停止された場合は null を返します。
  4. ローカル変数のみを使用するようになりました。
  5. おまけに、2 番目の変更が行われるとすぐにリストが返されます。
于 2013-01-13T02:38:51.730 に答える
2

それをランナブルとしてエグゼキューター サービスに送信し、返された Future で必要なタイムアウトを指定して get を呼び出します。次に、タイムアウト例外のキャッチ ブロックで、将来をキャンセルできます。

編集:コードサンプル

import com.google.common.base.Throwables;

import java.util.concurrent.*;

public class ExecutorExample {
  private static final ExecutorService executor = Executors.newSingleThreadExecutor();

  public void example() {
    Future<String> future = executor.submit(new Callable<String>() {
      @Override
      public String call() throws Exception {
        return "Do your complicated stuff";
      }
    });

    try {
      future.get(4, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      Throwables.propagate(e);
    } catch (ExecutionException e) {
      //handle
    } catch (TimeoutException e) {
      future.cancel(true);
    }
  }
}
于 2013-01-13T02:28:35.750 に答える
1

このような方法でうまくいきますが、注意してください。

public static void main(String[] args){
    Runnable fooRunner = new Runnable(){ public void run(){
        foo();
    }

    Thread fooThread = new Thread(fooRunner);
    fooThread.start();

    Thread.sleep(4000);

    fooThread.stop(); //warning -- this is deprecated!
}

問題は、Thread.stop非推奨であることです。

Java でのマルチスレッド化は、基本的に共同作業です。おそらく現在所有しているロックによって保護されている共有状態を操作している可能性があるためfoo()、任意の時点で停止することは潜在的に非常に危険であり、後でプログラムで予期しない障害やバグなどにつながる可能性があります。(実際、fooの戻り値の型はvoidであるため、結果を格納するために、ある時点で何らかの共有状態を操作する必要があります。)

Thread.interrupt()この言語は、次の便利なポイント ( 、Thread.interrupted()、および)で停止する必要があることをスレッドに伝える方法を提供しますInterruptedException。メソッドfoo()は、定期的に中断されたかどうかを確認する必要があります。それが行われる方法であり、高レベルのライブラリ構造 ( などFuture.cancel()) はこれに依存しています。

于 2013-01-13T02:31:44.923 に答える
0

スレッド化されたコードを書くという地獄のような領域に足を踏み入れなければなりません。

http://docs.oracle.com/javase/tutorial/essential/concurrency/

疑似コード (Apache Commons http://commons.apache.org/lang/download_lang.cgiで利用可能な可変ブール値)

...
final MutableBoolean finished = new MutableBoolean(false);
new Thread(new Runnable(){
    public void run() {
        doComplicatedStuff(finished);
    }
}).start();

Thread.sleep(4000);
finished.setValue(true);
于 2013-01-13T02:23:57.490 に答える