2

(以下の編集を必ずお読みください。この質問は明らかに混乱を招きます。申し訳ありません)

典型的なSwingUtilities.invokeLater呼び出しは次のとおりです。

  SwingUtilities.invokeLater( new Runnable() {
    public void run() {
       ...
    }
  } );

今、私は何になるかを知りたいSwingUtilities.invokeNowOrLaterIfEDTです。

もちろん、次のような独自のユーティリティクラスを使用することもできます。

public static void invokeNowOrLaterIfEDT( @NotNull Runnable r ) {
    if ( SwingUtilities.isEventDispatchThread() ) {
        Thread t = new Thread( r );
        t.start();
    } else {
        r.run();
    }
}

ただし、これには、EDTから呼び出されるたびに新しいスレッドが作成されるという欠点があります(そして、その新しいスレッドがスケジュールされるのを待つ必要があります)。

これを行う別の方法は、アプリのライフサイクル中に実行されている1つの追加スレッド(遅延インスタンス化される可能性があります)を使用して、ブロッキングキューを使用してをエンキューすることRunnablesです。利点は、EDTからそのようなメソッドを呼び出すたびにスレッドが常に作成されるとは限らないことです。

このようなものがデフォルトのJavaAPIに存在しますか?

上記の例のように、EDTから呼び出されるたびに新しいスレッドを作成するかRunnables、EDTの外部で実行されるスレッドを1つ追加するだけで、キューに入れられますか?

編集:EDTから呼び出される場合と呼び出されない場合と同様SwingUtilities.invokeLaterに、私が考えていたメソッドはEDTから呼び出される場合と呼び出されない場合があります。GUI / EDTでのユーザーアクションからトリガーされる場合とされない場合がある、完全に非同期の何かを実行することです。SwingUtilities.invokeLaterEDTを使用しているかどうかに関係なく、EDTを呼び出すときに気にせずに、EDTで何かを実行できると非常に便利だと思います。invokeNowOrLaterIfEDT(...)そして、上で示したものはとても便利だと思います。しかし、私はそれについて誤解されているかもしれません。そのような方法の必要性は狂っていますか?今、私は疑い始めています!?

編集2:私はまったくはっきりしていません、そして私はそれを理解します、それについて申し訳ありません。EDTからではなく非同期で実行したいのは、非常に長いプロセスではなく、プログレスバーや何が起こっているかを示すものなどの更新は必要ありません。シングルスレッド/キューに入れられている場合も問題ありません(明らかに、質問で述べました)。さまざまなコアなどに負荷を効率的に分散するためのスレッドプールをまったく求めていません。これらはEDTで実行する必要がなく、EDTから呼び出されるかどうかに関係なく、小さな計算であるだけです。これは、EDTの外部で実行したい非常に小さな非同期のものです。それらがすべて同じスレッドなどでキューに入れられている場合は問題ではありません。

しかし今、あなたの答えのおかげで、そのようなものが単一のスレッドと実行可能なキューを使用して実装された場合、長い計算のためにそのようなユーティリティメソッドを呼び出すことによって足で自分自身を撃つことは非常に簡単であることもわかりますその後、正しくマルチスレッド化されるのではなく、すべてがキューに入れられます。

4

3 に答える 3

3
  1. どのような場合でも、メソッドの実行可能ファイルが EDT で実行されることはないため、これが本当にやりたいことだと確信していますか。
  2. さて、あなたの答えとして、このメソッドを呼び出すことができるスレッドの数と頻度に応じて、ThreadPool を使用する必要があると思います。同時実行パッケージでThreadPoolExecutorおよびその他の APIを使用することをお勧めします。

ThreadPoolExecutor や Executors などの java.util.concurrent API を使用する利点の 1 つは、直接 API を呼び出すだけで多くのパラメーターとプーリング システム全体を微調整できることです。

于 2010-02-06T03:26:56.140 に答える
2

( Surajのに加えて)別のオプションは、を使用することSwingWorkerです。

このクラスは、あなたがやりたいことのために特別に設計されています。EDTから(おそらく長時間実行されている)プロセスを取得し、別のスレッドで実行します。にSwingWorkerは、すべてのスレッドコンテキストスイッチを処理できるという利点があります。また、スレッドを気にすることなく、EDTに更新を提供することもできます(たとえば、進行状況バーを表示するため)。

于 2010-02-06T03:41:33.440 に答える
2

あなたの質問は、「非同期呼び出しごとに新しいスレッドを作成するか、専用のスレッド/スレッドプールを使用する方が良いか」に要約されるようです?

残念ながら、答えは「場合による」と思います。これらのタスクが短くまれであることがわかっている場合は、新しいスレッドで問題ないでしょう。長い計算が互いにブロックすることが心配な場合は、おそらくスレッド プールが必要です。

static ExecutorService ex = Executors.newCachedThreadPool();

public static void invokeOutsideEDT(Runnable r) {
    if (SwingUtilities.isEventDispatchThread()) {
       ex.submit(r);
    } else {
        r.run();
    }
}

Suraj が指摘したように、concurrentパッケージには、ここで多くの既成の選択肢が用意されています。Executors.newCachedThreadPool()上記で使用したスレッドは、必要に応じてスレッドを追加し、古いスレッドを再利用します。ただし、Executors.newSingleThreadExecutor()代わりに、長時間実行されるタスクが本当に問題であるかExecutors.newFixedThreadPool()どうかを確認するか、設定された数のスレッドで使用してn、一部のタスクが長時間実行されている場合でも並行タスクを常に処理できるようにすることができます。

于 2011-10-07T18:58:08.220 に答える