简体   繁体   中英

Can't get String from GUI thread to 'logic' thread in java

I've been writing a program that searches through a list of numbers to find the ones that add up to a certain other number. No problems there, the algorhythm is, while probably not very efficient, functional.

Right now the list of numbers has to be taken from a text file, but I've been trying to make it so that the user can copy-paste a list into a TextArea, hit enter, and have the program send the String back to the normal (non-GUI) thread.

To do so I followed this example (the top answer). I'm using a key event instead of a button press, and a string instead of a linked list, but other than that, pretty similar.

Code where I create and run TextDemo (yes, I adapted a tutorial program):

  /*Copy paste text in window */
  public static String copypaste() throws Exception{
    String text = "";
    final TextDemo demo = new TextDemo();
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        demo.createAndShowGUI();
      }
    });
    synchronized(demo.text){
      while(demo.text.equals("")){   //if the window is unused
        demo.text.wait();
      }
      text = demo.text;
    }
    return text;
  }

TextDemo itself (minus the disclaimer, please don't alert Oracle :) ):

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class TextDemo extends JPanel implements KeyListener{
    protected JTextArea textArea;
    private final static String newline = "\n";
    public String text = "";
    boolean used = false;

    public TextDemo() {
        super(new GridBagLayout());

        textArea = new JTextArea(100, 30);
        textArea.addKeyListener(this);

        textArea.setEditable(true);
        JScrollPane scrollPane = new JScrollPane(textArea);

        //Add Components to this panel.
        GridBagConstraints c = new GridBagConstraints();
        c.gridwidth = GridBagConstraints.REMAINDER;

        c.fill = GridBagConstraints.BOTH;
        c.weightx = 1.0;
        c.weighty = 1.0;
        add(scrollPane, c);
    }

    public void keyPressed(KeyEvent e) {
        // Listen for the key pressed and check it against "Enter"
        // Then read out of our textarea control and print to screen4       
        if (e.getKeyCode() == e.VK_ENTER) {
          synchronized(text){
            text = textArea.getText();
            System.out.println("Text entered.");
            text.notify();
          }
            }
    }

    public void keyReleased(KeyEvent e) {
        // Listen for the key pressed and check it against "Enter"
        // Then read out of our textarea control and print to screen4       
        if (e.getKeyCode() == e.VK_ENTER) {
            //do nothing
        }
    }

    public void keyTyped(KeyEvent e) {
        // Listen for the key pressed and check it against "Enter"
        // Then read out of our textarea control and print to screen4       
        if (e.getKeyCode() == e.VK_ENTER) {
            //do nothing
        }
    }


    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event dispatch thread.
     */
    public static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("TextDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Add contents to the window.
        frame.add(new TextDemo());

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event dispatch thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }

}

When I run the code, it seems to work, until I hit enter and my program crashes. Error code (I'm only including the first 5 lines, the full version is here: http://img.photobucket.com/albums/v242/ChaosGuide/illegalmonitorstateexception.png ):

Exception in thread "AWT-EventQue-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at TextDemo.keyPressed(TextDemo.java:72)
    at java.awt.Component.processKeyEvent(Component.java:6463)
    at javax.swing.JComponent.processKeyEvent(JComponent.java:2829)
    at java.awt.Component.processEvent(Component.java:6282)

This is the first time I've done anything that even touches on threading, so I really don't understand what I'm doing wrong.

Any help is greatly appreciated.

Both threads use demo.text as their lock, and call wait() and notify() on this object to communicate, inside a synchronized block on demo.text , which is correct. But you're reassigning a new value to this variable just before calling notify() . So, in effect, you call notify() on an object which you don't own the lock:

synchronized(text) { // this block is synchronized on the empty string object
    text = textArea.getText(); // you assign another string to text
    System.out.println("Text entered.");
    text.notify(); // you call notify on this other string object, but you don't own its lock, because you synchronized on the empty string
}

Rule of thumb : when a variable is used as a lock, it should be final, to avoid this kind of bug. Moreover, using the empty string as a lock is a really, really bad idea. You'd better create a dedicated object to do that:

private final Object lock = new Object();

But the best thing to do would be to forget about wait() and notify() , which are too low-level, and to use a higher-level abstraction from the java.util.concurrent package like a semaphore for example.

Or even better: instead of having the main thread wait for the event dispatch thread, you'd better start a background thread, or rather use a SwingWorker, to execute your lengthy operation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM