1

メソッドで synchronized キーワードを使用すると、一度に 1 つのスレッドしかそのメソッドを実行できませんが、EDT はそのメソッドで同時に実行される複数の「イベント」を処理できます。デモンストレーションについては、以下のサンプル コードを参照してください。テスト ボタンをクリックすると、出力は次のようになります。

0 before dialog, EDT=true
1 before dialog, EDT=true
(click OK button for 1 here)
1 after dialog, EDT=true
(click OK button for 0 here)
0 after dialog, EDT=true

私が探しているのは、test() メソッドで一度に 1 つの EDT イベントのみをアクティブにして、出力が次のようになる方法です。

0 before dialog, EDT=true
(click OK button for 0 here)
0 after dialog, EDT=true
1 before dialog, EDT=true
(click OK button for 1 here)
1 after dialog, EDT=true

誰かが以前にこの問題を解決したに違いないようです。メソッドの開始時に使用する何らかのロック オブジェクトを記述したり、メソッドをラップしたりすることは可能だと思いますが、怠け者なので、車輪を再発明したくはありません。

私のテストケース:

package test1;

import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class EDTSyncTest extends javax.swing.JFrame {
  private static final Object locker = new Object();

  private int counter;

  public EDTSyncTest() {
    initComponents();
  }

  private synchronized void test() {
    int l_id = counter++;
    logit("" + l_id + " before dialog, EDT=" + SwingUtilities.isEventDispatchThread());

    JOptionPane l_pane = new JOptionPane("test id " + l_id);
    JDialog l_diag = l_pane.createDialog(this, "test");
    l_diag.setModal(true);
    l_diag.setVisible(true);

    logit("" + l_id + " after dialog, EDT=" + SwingUtilities.isEventDispatchThread());
  }

  private void startTest() {
     new Delayer().execute();
     test();
  }

  private static void logit(String a_msg) {
    System.out.println(a_msg);
  }

  private class Delayer extends SwingWorker<Object, Object> {
    @Override
    protected Object doInBackground() throws Exception {
      Thread.sleep(2000);
      return null;
    }
    @Override
    protected void done() {
      test();
    }
  }

  private void initComponents() {

    jButton1 = new javax.swing.JButton();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    getContentPane().setLayout(new java.awt.FlowLayout());

    jButton1.setText("Test");
    jButton1.setName("jButton1"); // NOI18N
    jButton1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        jButton1ActionPerformed(evt);
      }
    });
    getContentPane().add(jButton1);

    pack();
  }

  private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    startTest();
  }                                        

  public static void main(String args[]) {

    java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
        new EDTSyncTest().setVisible(true);
      }
    });
  }
  protected javax.swing.JButton jButton1;
}
4

2 に答える 2

5

さて、これがミリムースのサポートに導かれた私の答えです:D

これらの観察から始めましょう。

  • EDT スレッドは1 つだけです
  • スレッドには実行コンテキストが1 つしかありません
  • モーダル ダイアログは現在の実行コンテキストをブロックします
  • SwingWorker.done は常に EDT で呼び出されます

したがって、モーダル ダイアログはスイング イベントをブロックできません。そうしないと、UI 全体が応答しなくなります。では、swing イベントをブロックせずにブロックするにはどうすればよいでしょうか。

モーダル ダイアログは、独自のイベント ディスパッチ ループを実行します。次に、コード実行コール グラフ ( SwingWorker の完了後に EDT スレッドで完全に実行される) は次のようになります。

-> done (process FIRST done)
  -> 0/before
    -> modal dialog event loop (process NEXT done)
      -> 1/before
        -> modal dialog event loop (TOP DIALOG)
        <- OK PRESSED
      <- 1/after
    <- OK PRESSED
  <- 0/after 
<- back to normal EDT event loop

したがって、モーダル ダイアログは実行中にスイング イベントを処理しますが、「再帰的」な方法で処理します。

于 2013-05-28T23:56:29.360 に答える
1

私は自分自身を理解したばかりですが、@ millimooseがコメントしたように:

メソッドは同時に呼び出されているのtest()ではなく、再帰的に呼び出されているだけです。

コードを少し変更すると、次のようになります。

logit("" + l_id + " before dialog, EDT="
    + SwingUtilities.isEventDispatchThread());
new Throwable().printStackTrace(System.out);

出力:

0 before dialog, EDT=true
java.lang.Throwable
    at EDTSyncTest.test(EDTSyncTest.java:22)
    at EDTSyncTest.startTest(EDTSyncTest.java:35)
    at EDTSyncTest.jButton1ActionPerformed(EDTSyncTest.java:75)
    at EDTSyncTest.access$1(EDTSyncTest.java:74)
    at EDTSyncTest$1.actionPerformed(EDTSyncTest.java:66)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    /* ... */
    at java.awt.EventDispatchThread.run(Unknown Source)
1 before dialog, EDT=true
java.lang.Throwable
    at EDTSyncTest.test(EDTSyncTest.java:22)
    at EDTSyncTest.access$0(EDTSyncTest.java:17)
    at EDTSyncTest$Delayer.done(EDTSyncTest.java:51)
    at javax.swing.SwingWorker$5.run(Unknown Source)
    /* ... */
    at java.awt.Dialog.setVisible(Unknown Source)
    at EDTSyncTest.test(EDTSyncTest.java:27)
    at EDTSyncTest.startTest(EDTSyncTest.java:35)
    at EDTSyncTest.jButton1ActionPerformed(EDTSyncTest.java:75)
    at EDTSyncTest.access$1(EDTSyncTest.java:74)
    at EDTSyncTest$1.actionPerformed(EDTSyncTest.java:66)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    /* ... */
    at java.awt.EventDispatchThread.run(Unknown Source)
1 after dialog, EDT=true
0 after dialog, EDT=true
于 2013-05-28T23:53:12.833 に答える