4

Java スレッドを使用して常に何らかの操作を実行する Swing アプリケーションがあります。この操作の結果により、UI のグラフの内容が更新されます。

class ExampleThread {
    ... 
    public void run() {
        while (running) {
            // extract some information
            ...

            // show results in UI
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                     // use information to update a graph
                }
            });

            // sleep some seconds
            ...
        }
    }
    ...
}

私が抱えている問題は、EDT が他の操作で肥大化した場合です。この場合、はグラフを更新するExampleThreadさまざまなインスタンスを登録できます。Runnable私のアプリケーションでは、グラフが結果を表示する前に数回更新されるため、時間の無駄になります。私が望むのは、//update a graphコードを EDT サイクルごとに最大 1 回実行することです。

Runnable私の質問は、 aが一度だけ実行されるようにする適切な方法は何ですか?

4

3 に答える 3

5

アトミックなダーティ フラグでうまくいくはずです。これには、必要な場合にのみ EDT キューに追加するという追加の利点があります。大きな仮定 - 抽出された情報を保持するデータ構造はスレッドセーフですが、上記のコードが正しく機能するには、これが当てはまる必要があります。そうでない場合は、他の回答に示されている SwingWorker アプローチを検討する必要があります。また、dirty フラグと組み合わせて、冗長な更新を防ぐこともできます。

AtomicBoolean dirty = new AtomicBoolean(false);
while (running) {
        // extract some information
        ...

        if (!dirty.getAndSet(true)) {            
          SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                if (dirty.getAndSet(false)) {
                   // use information to update a graph
                }
              }
          });
        }

        // sleep some seconds
        ...
    }
于 2010-11-16T16:13:13.880 に答える
3

SwingWorkerを使用し、publishメソッドを利用して、更新をEDTに公開することをお勧めします。EDTは、次にスケジュールされたときに1つ以上の更新を適用します。たとえば、計算結果がIntegerインスタンスであるとします。

// Boolean flag to determine whether background thread should continue to run.
AtomicBoolean running = new AtomicBoolean(true);

new SwingWorker<Void, Integer>() {
  public Void doInBackground() {
    while (running.get()) {
      // Do calculation
      Integer result = doCalculation();

      publish(result);
    }
  }

  protected void process(List<Integer> chunks) {
    // Update UI on EDT with integer results.
  }
}

別のアプローチは、スケジュールされるたびに結果Runnableを単純に消費する単一のインスタンスを作成することです。Queueこれは、内部で動作する方法と似ていますが、実装を制御し、プールされたスレッドの1つを永続的に保持することを回避SwingWorkerできるという点で、わずかに制御が強化されます。QueueSwingWorker

private final Queue<Integer> resultQueue = Collections.synchronizedList(new LinkedList<Integer>());
// Thread-safe queue to hold results.    

// Our re-usable Runnable to be run on the EDT.  Consumes all results from the result queue
// before releasing the lock, although could obviously change this to consume up to N results.
Runnable consumer = new Runnable() {
  public void run() {
    synchronized(resultQueue) {
      Integer result;

      while ((result = resultQueue.take()) != null) {
        // Update UI.
      }
    }
  }
}

...

// Business logic to run on background thread.  Conditionally schedules the EDT to run as required.
while (true) {
  Integer result = doCalculation();

  synchronized(resultQueue) {
    boolean scheduleEdt = resultQueue.isEmpty();
    // Queue was empty before this result is added so need to schedule the EDT to run again.

    resultQueue.add(result);
  }

  if (scheduleEdt) {
    SwingUtilities.invokeLater(consumer);
  } else {
    System.err.println("EDT already scheduled -> Avoiding unecessary reschedule.");
  }
}
于 2010-11-16T15:53:54.753 に答える
0

あるいは、javax.swing.Timer.

于 2010-11-16T16:01:44.000 に答える