waiting on a thread joining

J

johnmmcparland

Hi all,

is there some way I can get my main thread to perform an action whilst
waiting on another to finish executing?

e.g.

while (!someObj.finishedLoading())
{
setCursor(Cursor.WAIT_CURSOR);
sleep(1000);
}

where someObj was initialised in a separate thread earlier on?

public class Example
{
// Has to be static and is some sort of chunky GUI
private static SomeObj someObj = null;
private JButton button = new JButton("Start");

public Example()
{
(new Thread(SomeObjRunner())).start();
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
// By now someObj needs to be fully
initialised
someObj.setVisible(true);
}
});
button.setEnabled(false);
waitOnAction();
}

private class SomeObjRunner implements Runnable
{
public void run()
{
someObj = new SomeObj();
}
}

public void waitOnAction()
{
// This is where I need to wait on someObj completing
while (!someObj.isFinished())
{
setCursor(Cursor.WAIT_CURSOR);
sleep(1000);
}
button.setEnabled(true);
}
}

The problem I'm currently having is that the button is enabled when
the someObj is still null.
 
S

Stefan Rybacki

johnmmcparland said:
Hi all,

is there some way I can get my main thread to perform an action whilst
waiting on another to finish executing?

e.g.

while (!someObj.finishedLoading())

while (someObj==null) might be a feasible solution

you could also join the thread that creates someObj or
you can use locks or you could use semaphores.
 
J

johnmmcparland

while (someObj==null) might be a feasible solution

you could also join the thread that creates someObj or
you can use locks or you could use semaphores.


 >...

That doesn't work, I get a null pointer exception on the action for
the button still.

I managed to solve it by using a single SwingWorker and a Timer;

BigGUI bigGUI = null;
Timer timer = null;
JButton button = null;
int timeCounter = 0;
StringBuffer timerText = null;
JEditorPanel htmlPanel = new JEditorPanel();

public ThisGUI()
{
if (null == ThisGUI.bigGUI)
{
SwingWorker worker = new SwingWorker()
{
public Object construct()
{
ThisGUI.bigGUI = new BigGUI();
return null;
}

public void finished()
{
while (!DataModel.instance().isFinishedLoading())
{
// While data model not loaded, set the cursor
the "waiting" state

setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
sleep(1000);
}
button.setEnabled(true);
// Stop showing the ellipses on the html panel
timer.stop();
htmlPanel.setText("");
// Back to ordinary cursor
setCursor(Cursor.getDefaultCursor());
}
};
worker.start();
}

ActionListener timerHandler = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
timerText.append(".");
if (timeCounter == 10)
{
timerCounter = 0;
int index = timerText.indexOf(".");
timerText.setLength(index);
}
htmlPanel.setText(timerText.toString());
timerCounter++;
}
};
timer = new Timer(1000, timerHandler);
timer.start();

button.setText("A button");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
// Show the bigGUI
ThisGUI.bigGUI.setVisible(true);
}
});
// Disable the button until the data model is loaded
button.setEnabled(false);
}
 
L

Lew

Hi all,

is there some way I can get my main thread to perform an action whilst
waiting on another to finish executing?

e.g.

while (!someObj.finishedLoading())
{
    setCursor(Cursor.WAIT_CURSOR);
    sleep(1000);

}

where someObj was initialised in a separate thread earlier on?

public class Example
{
    // Has to be static and is some sort of chunky GUI
    private static SomeObj someObj = null;
    private JButton button = new JButton("Start");

    public Example()
    {
        (new Thread(SomeObjRunner())).start();

Two problems here. This is not valid syntax, and even with the
insertion of 'new' you aren't advised to start threads from a
constructor. It publishes an incomplete 'this', likely the reason for
your bug.

Assuuming you fixed the syntax error in the real code.
        button.addActionListener(new ActionListener()
          {
                  public void actionPerformed(ActionEvent ae)
                  {
                           // By now someObj needs to be fully
initialised
                          someObj.setVisible(true);
                  }
          });
       button.setEnabled(false);
       waitOnAction();
    }

    private class SomeObjRunner implements Runnable
    {
        public void run()
        {
            someObj = new SomeObj();
        }
   }

   public void waitOnAction()
   {
         // This is where I need to wait on someObj completing
         while (!someObj.isFinished())
         {
               setCursor(Cursor.WAIT_CURSOR);
               sleep(1000);
         }
         button.setEnabled(true);
   }

}

The problem I'm currently having is that the button is enabled when
the someObj is still null.

It seems likely to me that starting a thread from the constructor,
publishing the unconstructed 'this', and the utter lack of care to put
GUI events on the EDT are at fault here.
 
L

Lew

johnmmcparland said:
That doesn't work, I get a null pointer exception on the action for
the button still.

You haven't solved the real problem.
I managed to solve it by using a single SwingWorker and a Timer;

BigGUI bigGUI = null;

Why are you initializing 'bigGui' to 'null' twice?
Timer timer = null;
JButton button = null;
int timeCounter = 0;
StringBuffer timerText = null;
JEditorPanel htmlPanel = new JEditorPanel();

public ThisGUI()
{
      if (null == ThisGUI.bigGUI)

Well, of course it's null. This test accomplishes nothing.
        {
            SwingWorker worker = new SwingWorker()
            {
                public Object construct()
                {
                    ThisGUI.bigGUI = new BigGUI();
                    return null;
                }

                public void finished()
                {
                    while (!DataModel.instance().isFinishedLoading())
                    {
                        // While data model not loaded, set the cursor
the "waiting" state

setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                        sleep(1000);
                    }
                    button.setEnabled(true);
                    // Stop showing the ellipses on the html panel
                    timer.stop();
                    htmlPanel.setText("");
                    // Back to ordinary cursor
                    setCursor(Cursor.getDefaultCursor());
                }
            };
            worker.start();

Don't start threads from the constructor.
        }

        ActionListener timerHandler = new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                timerText.append(".");
                if (timeCounter == 10)
                {
                    timerCounter = 0;
                    int index = timerText.indexOf("..");
                    timerText.setLength(index);
                }
                htmlPanel.setText(timerText.toString());
                timerCounter++;
            }
        };
        timer = new Timer(1000, timerHandler);
        timer.start();

Don't start threads from the constructor.
        button.setText("A button");
        button.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                // Show the bigGUI
                ThisGUI.bigGUI.setVisible(true);
            }
        });
        // Disable the button until the data model is loaded
        button.setEnabled(false);

}

The whole 'Timer' thing is a hack, avoidable if you don't put all that
work in the constructor.
 
R

RedGrittyBrick

johnmmcparland said:
Hi all,

is there some way I can get my main thread to perform an action whilst
waiting on another to finish executing?

Use EventQueue.invokeLater early to switch to the GUI thread (EDT), then
use SwingWorker to launch slow stuff in the background and to perform
GUI updates when that thread has completed.

Something like

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable(){
public void run() {

// GUI thread (EDT)
container.setCursor(Cursor.WAIT_CURSOR); // ****

new SwingWorker<Void><Void>() {

// background thread
protected Void doInBackground() throws Exception {
someObj = new SomeObj(); // ****
return null;
}

// GUI thread (EDT)
protected void done() {
someObj.setVisible(); // ****
// you need to pack or invalidate container?
container.setCursor(Cursor.DEFAULT_CURSOR); // ****
}

}.execute();
}
});
}

Untested code but an idiom I use often and successfully.

I'd move the slow stuff out of someObj's constructor into a separate method.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top