0

I have an application that uses a JTabbedPane to show several different tabs. One of these tabs has a thread running to display it's contents. I have already implemented a ComponentListener to stop the thread when the tab is not visible. I can see the thread becoming active when the tab is selected and stopping when becoming invisible, quite as expected.

If I close my application when the tab with the thread is not selected, everything goes well and the application closes. If I close my application when the tab with the thread is visible, the tab does not receive a ComponentEvent, so the thread stays active and I need to kill the application by hand (using the Terminate button on the console in Eclipse).

I prefer not to use the System.exit() method to close my application, but rather stop all threads and dispose all windows. This is working like a charm, except for this one tab with it's thread.

I have already tried to set the JTabbedPane to invisible before disposing my window, or removeAll(). Neither had the expected result. The removeAll() even had the opposite result. If the tab was not active, it would receive a ComponentEvent to indicate that is had become visible (componentShown) (actually, all tabs would receive the event in turn, but none would get a componentHidden).

Obviously, the thread should be stopped both when I close the window via the file menu (over which I have some control and where I have tested the removeAll and setVisible(false) methods) as well as when the window is disposed because the user clicks on the cross in the window corner.

Update

I have found a way to make the thread that seems to cause the problem run as daemon thread as suggested. This has however led to an unexpected problem. The class that started the problematic thread was the VisRunner class from the JUNG software package I am using. It contains a method "relax" in which the thread is started.

  @Override
  public void relax() {
      // in case its running
      stop();
      stop = false;
      thread = new Thread(this);
      thread.setPriority(Thread.MIN_PRIORITY);
      thread.start();
 }

I have created the MyVisRunner class:

import edu.uci.ics.jung.algorithms.layout.util.VisRunner;
import edu.uci.ics.jung.algorithms.util.IterativeContext;

public class MyVisRunner extends VisRunner {

   public MyVisRunner(final IterativeContext process) {
      super(process);
   }

   @Override
   public void relax() {
      // in case it's running
      Log.d("Relaxing");
      stop();
      stop = false;
      thread = new Thread(this);
      thread.setPriority(Thread.MIN_PRIORITY);
      thread.setDaemon(true);
      thread.start();
   }
}

I load the relaxer as such:

  visModel = new DefaultVisualizationModel<>(layout);
  visModel.setRelaxer(new MyVisRunner(layout));

I would have expected this to solve the problem, but it only increases the problem. When I now start my software, it will not stop, even when the problematic tab is not even visible (the tab is constructed, but is not visible). The relax method from MyVisRunner has not even been called in that case; the thread is not initialized anywhere else in the VisRunner class. Commenting out the setRelaxer line will solve this additional problem (obviously keeping the original problem).

Update 2

I have solved the problem finally. I didn't realize that when I set my own relaxer, there was already a relaxer running. I have adjusted the code to:

  visModel = new DefaultVisualizationModel<>(layout);
  visModel.getRelaxer().stop();
  visModel.setRelaxer(new MyVisRunner(layout));

This has solved both the additional problem as well as my original one.

Stefan
  • 3
  • 2
  • Obviously, other methods (other than the ComponentEvent) of solving this problem are welcome as well. – Stefan Feb 26 '13 at 08:25
  • Did you use `Thread.setDaemon(true)` ? – oliholz Feb 26 '13 at 08:27
  • @oliholz, see my reactions to MouseEvent's answer on the Thread.setDaemon(). – Stefan Feb 26 '13 at 08:37
  • Which Thread is still alive? The `VisRunner`? You can stop the Relaxer manually by `myDefaultVisualizationModel.getRelaxer().stop()` – oliholz Feb 26 '13 at 09:16
  • The suspect is indeed the VisRunner. The problem with your approach is that the main window (the one with the JTabbedPane) does not know anything about the VisRunner. The tab that contains the JUNG bits already calls the stop() on the relaxer when it gets a visibility change to not visible. – Stefan Feb 26 '13 at 09:44

1 Answers1

1

You should set the thread as a daemon thread:

myThread.setDaemon(true);

A Virtual Machine will terminate if there are no more running non-daemon threads.


BTW you can add a WindowListener on your JFrame for windowClosing events.

Mordechai
  • 15,437
  • 2
  • 41
  • 82
  • Thanks for the tip, I did not know that detail. Unfortunately, the thread that is running is a thread in a third party library, which I would prefer not to have to modify, although I could ask them to change their thread to a non-daemon thread. – Stefan Feb 26 '13 at 08:33
  • @Stefan well, if you can get a reference to that thread, you can change it yourself. – Mordechai Feb 26 '13 at 08:35
  • unfortunately, the library (JUNG, [link](http://jung.sourceforge.net/)) does not give me a reference to the thread. – Stefan Feb 26 '13 at 08:42
  • I have now been able to work around this by subclassing the class that creates the thread (fortunately, the class had a protected handle to the thread I could get to). However, the software still keeps running, so I'm now searching for additional threads ;( – Stefan Feb 26 '13 at 09:37
  • The updates in the question show what caused the software to keep running regardless of my adaptation. – Stefan Feb 26 '13 at 10:17