Java: GUIs must be initialized in the EDT thread? - java

I'm Jason. I'm having a bit of a problem with the Substance look and feel (https://substance.dev.java.net/).
My problem is more general. I've already got my GUI written and it works fine, but when I use a Substance Look-and-feel, it requires all GUI initialization to take place in the EDT thread (Event Dispatching Thread or something).
Right now I'm using com.sun.java.swing.plaf.windows.WindowsLookAndFeel (not sure if I spelled that right) and it doesn't require anything of this sort.
So I put the main initialization into the EDT by calling SwingUtilities.invokeLater(). This made it work. However, the program also spawns several other windows during its execution. Right now I have code like:
SomeNewWindow window = new SomeNewWindow();
// ... some bs emitted
window.doStuff();
This code works fine because by the time window.doStuff() is called, it's already initialized. But Substance requires me to do something like this:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
SomeNewWindow window = new SomeNewWindow();
}});
// ... bs emitted
window.doStuff();
Here it sometimes throws a NullPointerException because window is not initialized by the time window.doStuff() is called. I can't put window.doStuff() into the EDT thread because it usually takes several seconds to return and will hang the GUI.
I've tried putting Thread.sleep(1000) right after I invoke the EDT thread because it's probably initialized by then. But this seems awkward. I simply need a way for the main thread to 'know' when the SomeNewWindow initialization has returned so it can continue on without having to worry about a NullPointerException.
Thanks in advance.

You could switch from invokeLater to invokeAndWait, which will wait until the window is created. It's a bit cheesy, but not as bad as putting in a sleep.

I think the standard approach to this would be to make your EDT the "base thread" from which you start other worker threads to do stuff.
Another way would be to use a volatile flag that the initializer can set when it's done, so the other thread can check it in a loop and act on the new window once the flag is set.

Egwor suggest using a CountDownLatch instead. Definitely looks like it would simplify the situation.
This is a job for condition variables.
Basically, in run(), Lock the lock, construct some new window and signal the condition (and unlock the lock).
"Meanwhile", in the other thread, do your other "bs", lock the lock; if the window is null, wait() on the condition variable; unlock the lock; window.doStuff();

Is there a reason why you can't just move the doStuff() call into the invokeLater callback?
SwingUtilities.invokeLater(new Runnable(){
public void run(){
SomeNewWindow window = new SomeNewWindow();
window.doStuff();
}
});
If the above is impossible, I'd go with invokeAndWait() instead of invokeLater(), as Paul Tomblin already suggested.

Related

Why can't I make a call to a function while in a thread?

I am multithreading a background process on a JFrame window, and I want to update the text of a global JLabel variable inside a function.
So when the thread runs, my while and for loops run, but during them running, it makes the call to that other function to change the text.
However, it doesn't update until the thread finishes executing (i.e when the loops finish). Any reason why this happens, and how I can fix this?
If I try to just change the text of the JLabel inside the thread, it has the same result.
What might happened is your thread did make the change, but the screen display is not updated until the Swing event dispatch thread comes around and updates the display. It is recommended and safer to call user interface updating methods using the Swing event dispatch thread. You can do this by putting gui update code inside this method:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// call gui update here
}
});
This still doesn't solve your problem yet (update happens after thread finish executing). This is only to make it explicit that you are dealing with two threads here. Your for loop on a separate thread will likely to finish first because the drawing thread is usually slower. However, knowing this will help you to plan which code to be passed to Swing event dispatch thread. If you really want the for loop to update at that point in time, then you can put the entire for loop inside the invokeLater().

New Window Doesn't Load

I need some help, I have a method which is performed when a button is clicked, this method then opens a new window that updates a variable in another class, the method then gets this variable from the class and then uses it.
The window that is loaded is blank, and it seems as if the wait() function is causing the thread to cease before the new window is loaded.
private void autoFillUsersActionPerformed(java.awt.event.ActionEvent evt) {
publicLesson pL= new publicLesson();
new dateSelect().setVisible(true);
try{
synchronized(this){
this.wait();
}
}
catch(Exception e){
}
int var= pL.getAmount();
System.out.println("var ="+var);
DefaultTableModel defaultModel = (DefaultTableModel) pupilTable.getModel();
for (int i = 0; i <= (userCountAmount - 1); i++) {
defaultModel.setValueAt(var, 5, i);
System.out.println("BeingSet");
}
}
You are blocking the Event Dispatch Thread. By not allowing the EDT to move past the wait call, no events can be processed which means nothing can be painted.
Instead of using a new window, try using a modal dialog. Modal dialogs block all access to other top level components (depending on the modality type) until they are properly disposed of.
Yes, indeed. Waiting on the event dispatch thread makes it block completely, and thus prevents any repaint to happen. So the EDT can't paint anything anymore while you're waiting.
Long-running tasks, and even more blocking tasks, should not be done in the event dispatch thread. It's not clear at all why you're using wait() here, BTW.
And catching Exception and ignoring it completely is one of the worst things you could do.
wait method is inherited from Object() and the docs state
Causes current thread to wait until another thread invokes the
notify() method or the notifyAll() method for this object. In other
words, this method behaves exactly as if it simply performs the call
wait(0).
Hence, you must give it something to wait for, but as you are blocking the only thread, there's no way it paints something in the meanwhile.
Is it your aim to wait in your main JFrame until the User entered the data you need in another JFrame ?
if thats your aim just have a look at Dialog ModalityTypes.
http://download.java.net/jdk7/archive/b123/docs/api/java/awt/Dialog.ModalityType.html
When constructing the new Dialog just give the parent dialog as a prameter to the constructor and then call
super(parentDialog, Dialog.ModalityType.DOCUMENT_MODAL);
then your main JFrame will wait for your new JDialog to close until it runs the rest of the function.
Hope that helps.
You cannot do that way, because Swing runs on one thread only! You need to move the processing you are doing after wait, into that window you are creating. You cannot depend on wait.
Here is a good document to read:
http://www.javapractices.com/topic/TopicAction.do?Id=153
I agree with some answers: remove the try/catch/synchronized block and use javax.swing.JDialog to receive the user input.
Refer to the official Swing documentation, it provides good enough examples,
i.e. this one http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html regarding the JDialog.

How can I have a thread tell the method that started it when it has completed doing its setup?

I have a method that starts a thread, and I want to have the method block until the thread finishes its setup stage, or else face a race condition.
I know I want to use wait notify, but I don't know how to own the monitor and so on.
I generally use a Count down latch if only the starting thread needs to wait.
There are examples there but I can throw up a quicky example if you need it.
Or you could use a barrier if multiple threads are likely to use thread and need to know when it is initialized.
Move your "setup stage" out of run() and into an init() method.
MyRunnableClass mrc = new MyRunnableClass();
mrc.init();
Thread t = new Thread(mrc);
t.start();
Edit: Or as #Buhb noted in the comments below, just put it in the constructor. Years of C++ makes old habits die hard.

Java Threads -- Perpetual Loop in Swing Event Dispatch Thread

I have a SwingWorker with the implementation:
public Void doInBackground() throws InterruptedException
{
while (true)
{
while(_update)
{
}
}
}
If _update is set to false, is it safe to let the EDT perpetually go on a loop? Or should I let it sleep every second?
-- EDIT
It looks like I'm not using SwingWorker as it's supposed to be used. Thanks all. I'll stick to creating SwingWorkers as I need them.
It is not safe to let the Event Dispatch Thread go in a loop.
The event dispatch thread is needed to provide user interaction with the application. If you want an event to go off every few seconds, you should put it, or another copy of it, back on the event queue each time it has completed.
Why wouldn't you just start another thread and let it run/sleep as needed, and have it use SwingUtilities.InvokeLater or whatever to do UI work as necessary?
Without any other context it looks like you might be misusing SwingWorker?

Why is run() not immediately called when start() called on a thread object in java

Or is it?
I have a thread object from:
Thread myThread = new Thread(pObject);
Where pObject is an object of a class implementing the Runnable interface and then I have the start method called on the thread object like so:
myThread.start();
Now, my understanding is that when start() is called, the JVM implicitly (and immediately) calls the run() method which may be overridden (as it is in my case)
However, in my case, it appears that the start() method is not called immediately (as desired) but until the other statements/methods are completed from the calling block i.e. if I had a method after the start() call like so:
myThread.start();
doSomethingElse();
doSomthingElse() gets executed before the run() method is run at all.
Perhaps I am wrong with the initial premise that run() is always called right after the start() is called. Please help! The desired again is making executing run() right after start(). Thanks.
Um... the run() method will run in a different thread. That, per definition, means you cannot make any assumptions about before or after which statements in the current thread it will execute, unless you synchronize them explicitly.
Now, my understanding is that when start() is called, the JVM implicitly (and immediately) calls the run() method ...
That is incorrect. It does implicitly call run(), but the call does not necessarily happen immediately.
The reality is that the new thread becomes available to be scheduled at some point in time after the start() call is made. The actual scheduling is up to the native scheduler. It could happen immediately, or the parent thread could continue for a period before the child thread is scheduled.
To force your thread to start running immediately (or to be more accurate, to start running before doSomethingElse()), you need to do some explicit synchronization; e.g. something like this:
java.util.concurrent.CountDownLatch latch = new CountdownLatch(1);
new Thread(new MyRunnable(latch)).start();
latch.await(); // waits until released by the child thread.
doSomethingElse();
where
class MyRunnable implements Runnable {
private CountDownLatch latch;
MyRunnable (CountDownLatch latch) { this.latch = latch; }
public void run() {
doSomeStuff();
latch.countDown(); // releases the parent thread
doSomeMoreStuff();
}
...
}
There are other ways to implement the synchronization using the concurrency classes, or Java's mutex / wait / notify primitives1. But explicit synchronization between the two threads is the only way to guarantee the behavior that you require.
Note that the doSomething() call in the child thread will complete before the parent thread is released, but we can say nothing about the order of execution of doSomethingElese() and doSomeMoreStuff(). (One might run before the other and vice versa, or they might run in parallel.)
1 - Using wait / notify is not recommended, but it may be your only option if the concurrency APIs are not available; e.g. on Java ME.
run() is the first thing within your code that the new thread does, but there's some set-up work that the new thread does first, and there's no guarantee that any significant amount of work will by done by the new thread before the original thread goes on to call doSomethingElse().
You're right in thinking that there are no guarantees here. Making assumptions about the behaviour of multithreaded code is the source of much pain - try not to do it!
When you call myThread.start(), your thread becomes available for execution. Whether it will actually gain CPU, and for how long -- it's up the the OS scheduler. In fact, your run() may be getting control immediately, but losing it before it can do anything you can notice. The only way to ensure that your thread executes what you need before doSomethingElse() is to use explicit synchronization.
You've started a new thread. That thread runs in parallel to the thread that started it so the order could be:
pObject.run();
doSomethingElse();
or
doSomethingElse();
pObject.run();
or, more likely, there will be some crossover. pObject.run() may run in the middle of doSomethingElse() or vice versa or one will start before the other finishes and so on. It's important to understand this and understand what is meant by an atomic operation or you will find yourself with some really hard-to-find bugs.
It's even more complicated if two or more threads access the same variables. The value in one may never be updated in one thread under certain circumstances.
I highly suggest:
You don't make your program multi-threaded unless you absolutely need to; and
If you do, buy and read from cover to cover Brian Goetz's Java Concurrency in Practice.
calling the start method on a Thread Object may not make the jvm invoke the run() method immidiately, rather it makes the thread a runnable and ready for execution, in this case the parent thread first executes its code and then passes control to the child thread, if u want the child thread to execute before the parent thread code is executed use the chileThreadObject.join() method in the parent thread.

Categories

Resources