事件调度线程同步

时间:2016-07-14 10:50:14

标签: java multithreading swing junit

更好地了解EDT同步如何工作

我创建了一个简单的JUnit3 Testcase - 见下文。目标是等待两个事件:

  1. 要创建的GUI / JFrame
  2. Textfield的修改
  3. 首先,我尝试对相应的布尔锁对象进行wait()调用,但这并没有按预期工作。然后我尝试了一个等待布尔锁内容的循环。这两种方法都不像我期望的那样有效。

    如何修改以下代码以获得预期的等待行为?

    JUnit Testcase

    package com.bitplan.test.common;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    import javax.swing.event.DocumentEvent;
    import javax.swing.event.DocumentListener;
    
    import junit.framework.TestCase;
    
    /**
     * test the event dispatching thread handling
     * 
     * @author wf
     *
     */
    public class TestEDT extends TestCase {
    
    
      private JTextField field;
      private  Boolean modified=new Boolean(false);
      private  Boolean created=new Boolean(false);
    
      /**
       * test UI handling
       * 
       * @throws InterruptedException
       */
      public void testUI() throws InterruptedException {
        // see
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            createAndShowGUI();
          }
        });
        synchronized(created) {
          created.wait();
          /**
          while(!created.isTrue()) {
            Thread.sleep(10);
          } */
        }
        field.getDocument().addDocumentListener(new DocumentListener() {
          public void flagModification() {
            synchronized(modified) {
              modified=true;
              modified.notify();
            }      
          }
          public void insertUpdate(DocumentEvent e) {
            flagModification();
          }
    
          @Override
          public void removeUpdate(DocumentEvent e) {     
            flagModification();
          }
    
          @Override
          public void changedUpdate(DocumentEvent e) {
            flagModification();        
          }
        });
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            updateField("fieldcontent");
          }
        });
        synchronized(modified) {
          // https://stackoverflow.com/questions/2536692/a-simple-scenario-using-wait-and-notify-in-java?noredirect=1&lq=1
          modified.wait();
          /**
          while(!modified) {
            Thread.sleep(10);
          } */
        }
      }
    
      /**
       * update the field with the new content;
       * 
       * @param newContent
       */
      protected void updateField(String newContent) {
        field.setText(newContent);
      }
    
      /**
       * create and show the given gui
       */
      protected void createAndShowGUI() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle("Example GUI");
        JPanel panel = new JPanel();
        field = new JTextField(30);
        panel.add(field);
        frame.setContentPane(panel);
        frame.pack();
        frame.setVisible(true);
        synchronized(created) {
          created=true;
          created.notify();
        }
      }
    }
    

1 个答案:

答案 0 :(得分:1)

如果使用“Lock”类,该方法有效。最初我使用了一个布尔值,但由于这些锁定对象被赋值所取代,所以它不起作用。

created=true. 

将创建一个新的单独的Boolean对象,因此created.notify()表示不同的对象,并且不会停止主线程中的等待。

Lock版本有效。我已将问题的代码更改回原来错误的布尔版本以显示重点。

package com.bitplan.test.common;

import java.awt.Frame;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import junit.framework.TestCase;

/**
 * test the event dispatching thread handling
 * 
 * @author wf
 *
 */
public class TestEDT extends TestCase {

  public static class Lock {

    boolean value;

    public Lock(boolean value) {
      super();
      this.value = value;
    } 
    /**
     * @return the value
     */
    public boolean isTrue() {
      return value;
    }

    /**
     * @param value the value to set
     */
    public void set(boolean value) {
      this.value = value;
    }
  }
  private JTextField field;
  private Lock modified=new Lock(false);
  private Lock  created=new Lock(false);

  /**
   * test UI handling
   * 
   * @throws InterruptedException
   */
  public void testUI() throws InterruptedException {
    // see
    // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    });
    synchronized(created) {
      while(!created.isTrue())
        created.wait();
    }
    field.getDocument().addDocumentListener(new DocumentListener() {
      public void flagModification() {
        synchronized(modified) {
          modified.set(true);
          modified.notify();
        }      
      }
      public void insertUpdate(DocumentEvent e) {
        flagModification();
      }

      @Override
      public void removeUpdate(DocumentEvent e) {     
        flagModification();
      }

      @Override
      public void changedUpdate(DocumentEvent e) {
        flagModification();        
      }
    });
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        updateField("fieldcontent");
      }
    });
    synchronized(modified) {
      while(!modified.isTrue())
      // http://stackoverflow.com/questions/2536692/a-simple-scenario-using-wait-and-notify-in-java?noredirect=1&lq=1
        modified.wait();
    }
  }

  /**
   * update the field with the new content;
   * 
   * @param newContent
   */
  protected void updateField(String newContent) {
    field.setText(newContent);
  }

  /**
   * create and show the given gui
   */
  protected void createAndShowGUI() {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.setTitle("Example GUI");
    JPanel panel = new JPanel();
    field = new JTextField(30);
    panel.add(field);
    frame.setContentPane(panel);
    frame.pack();
    frame.setVisible(true);
    synchronized(created) {
      created.set(true);
      created.notify();
    }
  }
}