0

I have another question for this forum. I am writing a small application with Java in which I have multiple Threads. I have two Threads that are in two different classes. I have one Thread (thread1) dedicated to defining all of the JFrame components. (JPanels, JButtons, ActionListeners, etc.) In another Thread, (thread2) I am checking for a variable (v) to equal a certain value. (98) When this variables does change to equal 98, that same thread is supposed to update a JLabel. (Let's call this label label for now.) It does not. Is there something I am doing wrong. I have tried writing a method for the class - that declares all of the JFrame components - that changes the text of label, but when I call this method from thread2 it does not update the label. I have tried calling a super class containing thread1, but that did not seem to make a difference. Also, I have been calling the repaint() method, but that does not seem to help.

Please let me know what I can do to update these JLabels from the two different Threads.

Thanks in advance, ~Rane

Code:

Class1:

JFrame frame = new JFrame();
JPanel panel = new JPanel();
JLabel label = new JLabel("V does not equal 98 Yet...");
Thread thread1 = new Thread(){

  public void run(){

    panel.add(label);
    frame.add(panel);
    System.out.println("Components added!");

  }
});

public void setLabelText(String text){
  label.setText(text);
}

Class1=2:

v = 0;
Thread thread2 = new Thread(){

  public void run(){

    while(v < 98){

      System.out.println("V equals -" + v + "-.");
      v ++;
    }
    Class1 otherClass = new Class1();
    otherClass.label.setText("V is now equal to: " + v);
    otherClass.repaint();
    otherClass.setLabelText("V is now equal to: " + v);
    otherClass.repaint();
  }
});
Rane
  • 191
  • 2
  • 13
  • 4
    Swing is a single threaded framework, it is also NOT thread safe, this means that all creation, ulceration so and modifications to any UI should be done from within the context of the Event Dispatching Thread. It also means y should not execute long running or blocking code within the context of the EDT as this will cause the program to appear as its hung (because it has). So the answer to your question is, NO, NEVER, EVER, should you be doing what your trying to do. Consider using a SwingWorker of using SwingUtilities.invokeLater to ensure that updates are synchronised back to the EDT... – MadProgrammer Oct 21 '14 at 20:12
  • Well said. Any thread can cause code to be executed in the AWT/ETD/Swing thread (all alternative names for the same) by `SwingUtilities.invokeLater()` – Mark Jeronimus Oct 21 '14 at 20:13
  • Remember, you shouldn't be doing it this way, but, you seem to be making two instances of Class1, the instance in thread 1 is not the same instance in thread 2, so changing one will have no effect on the other... – MadProgrammer Oct 21 '14 at 20:14
  • If you don't suggest I use Threads, how do you suggest that I update the JLabel? If JLabel is not Thread-safe, is there another similar GUI that you would recommend? – Rane Oct 21 '14 at 20:19
  • FYI, everything that your program does is "from a thread." Even if you program is just a simple console app that does not create any new threads of its own, it will run in the JVM's "main" thread, and the JVM will have several other threads running to do things like garbage collection & I don't know what else. – Solomon Slow Oct 21 '14 at 20:56
  • Have a look at [Concurrency in Swing](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) and [Worker Threads and SwingWorker](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html) for more details – MadProgrammer Oct 21 '14 at 21:04
  • Again, the links are all here, you just have to read them. – Hovercraft Full Of Eels Dec 06 '14 at 20:48

1 Answers1

9

Swing is not thread-safe. I repeat: do not call any methods on Swing objects from any threads other than the Event Dispatch Thread (EDT)

If you are getting events from multiple different threads and you want to have them directly affect Swing objects, you should use:

// Note you must use final method arguments to be available inside an anonymous class
private void changeJLabel(final JLabel label, final String text) {
  EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
      myLabel.setText(text);
    }
  });
}
durron597
  • 31,968
  • 17
  • 99
  • 158
  • 1
    @LifeH2O No, there's only one thread - the Event Dispatch Thread. This just schedules tasks for that thread to process. – durron597 Apr 20 '15 at 13:29
  • This http://stackoverflow.com/questions/9029795/new-runnable-but-no-new-thread explains `new Runnable(){}` – SMUsamaShah Apr 20 '15 at 14:11
  • Hi, I have the same problem but can't make the String final. It changes quite often during the run. Any Ideas? – Sudh33ra Jul 11 '16 at 11:36
  • @DonDrenai Feel free to ask a separate question. Note that I am not saying the string should be final, just that it should be declared final **as a method argument** from your `updateJLabel` function or whatever. You can still call such a method with different strings at different times during your program. – durron597 Jul 11 '16 at 18:04