views:

345

answers:

3

In a project I'm working on, I have a main class (named TrackWin) that extends JFrame. In this frame, I make use of a JTabbedPane.

A user can create a new tab in the pane from the Menu Bar. Whenever this occurs, tabbedPane.addTab() is called in TrackWin.

I also have a class called TrackTab, which extends JPanel. This class contains all the actual information for the new tab. Included in this class, is a Thread which calls a "3rd party" class (and group of classes) to perform a specific action whenever a JButton is clicked.

My problem is occuring however, whenever I make multiple tabs, and try to start more than one thread instance at a time. When I run the debugger (I'm using Eclipse), I noticed that the current set of Threads created whenever the JButton is clicked, are overwritten by another tab's thread instance.

However, I have to think that my problem is due to my own implementation, and not the nature of the "3rd party" class I'm making an instance of. Because, if I add more than one Thread instance to the TrackTab class (for example, Thread1 and Thread2, which both make/call new instances of the Third Party class), the debugger shows a set of Threads for each, and they run fine.

I'd appreciate any suggestions!

Here's some example code:

public class TrackWin extends JFrame {
    public JTabbedPane tabbedPane;

    public TrackWin()
    {
     tabbedPane = new JTabbedPane();
     TrackTab panel = new TrackTab();

        tabbedPane.addTab("Tab Name", null, panel,
                "Tab Instance");

        tabbedPane.updateUI();
        add(tabbedPane);

     /////////////////////////////////////////////////////////////
     // Initialize Menu Bar
     /////////////////////////////////////////////////////////////

      JMenuBar menuBar = new JMenuBar();
      JMenu menu;
     JMenuItem menuItem;

     menu = new JMenu("File");
     menu.setMnemonic(KeyEvent.VK_F);

     // New Tab Instance
     menuItem = new JMenuItem("New Instance");

     menuItem.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {

       TrackTab panel = new TrackTab();

       tabbedPane.addTab("Tab Name", null, panel, "Tab Instance");

          tabbedPane.updateUI();
          tabbedPane.repaint();
          tabbedPane.setVisible(true);
        }
     });
     menu.add(menuItem);
     setJMenuBar(menuBar);
     setVisible(true);
    }
}

TrackTab.java's Thread call:

thread = new Thread(new TrackThread(variable1, variable2, variable3));
thread.start();

wherein, 'thread' is a public global variable of TrackTab.

And then, the TrackThread class is simple:

public class TrackThread extends Thread {
    public int variable1;
    public int variable2;
    public int variable3;

    public TrackThread(int variable1, int variable2, int variable3) {
     this.variable1 = variable1;
     this.variable2 = variable2;
     this.variable3 = variable3;
    }

    public void run() {
     3rdPartyClass myPub = new 3rdPartyClass();
     myPub.do(variable1, variable2, variable3);
    }
}

I don't have a whole lot of information on the 3rd party class package (since I haven't delved into it too deeply), but I do know that there are some static variables that may cause problems. I recognize some refactoring may need done. However, I'd like to know if it's my code that is giving me the problems first.

What's weird, is that in TrackTab, if I add another instance of TrackThread and run them cocurrently from that single instance of TrackTab, all goes well). So weird. Please help!

+2  A: 

This might have nothing to do with the issue you are experiencing, but your line:

thread = new Thread(new TrackThread(variable1, variable2, variable3));

looks 'interesting' -- TrackThread itself extends Thread, you don't need to wrap another thread around it to run it. Either make TrackThread implement Runnable (and not extend Thread anymore), or just write:

thread = new TrackThread(variable1, variable2, variable3);

That should work just as well and saves the creation of an unneeded thread object.

Furthermore, when debugging threads it is very useful to name them so they are easier to distinguish. Use setName() or one of the constructors that take a name argument.

Simon Groenewolt
A: 

This seems odd:

"wherein, 'thread' is a public global variable of TrackTab."

If your intent is to run a 3rd party class in a separate thread, then you should not need a global reference to the thread.

TrackThread extends Thread

should be changed to

TrackRunnable implements Runnable

and the thread variable should be changed to local.

Thread thread = new Thread(new TrackRunnable(variable1, variable2, variable3));
thread.setDaemon(true);
thread.start();
Clint
The reason I have 'thread' as a global variable, is to I can kill it if I need to, with another JButton by using thread.stop(). The 'thread' process using the 3rd party classes runs over a period of time, and is not something quick to finish.
Monster
If it is a global variable than it will be written over on every new TrackTab. "thread" can be an instance variable of TrackTab. I would also look into Thread.interrupt() instead of Thread.stop();
Clint
Oh, I'm sorry. I meant instance variable. Gah!
Monster
A: 

In addition to Simon's observation and recommendation, I'd suggest that you minimise your unknowns.

In this case, that would mean mocking out your third party class. Replace it with something you know to not have any problematic statics. Nothing fancy, just a simple thread that runs and produces output somewhere.

CPerkins
Ah, true. I'll give it a try.
Monster