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?
Related
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().
It seems I miss a certain point in Java and Swing. The issue is as follows:
I have a swing GUI with a Start / Stop button (And some more)
It starts the function (What is set up as a thread in this case), Thread starts, it works, Swing GUI is fully operational and does all the other things it is made for, e.g. modifying parameters for the worker thread.
Of course, sending an interrupt to ask the thread to stop on users request is in and functions. So far so good.
But I did not found a way that Swing GUI notices the thread stopped on its own:
If I ignore it, it confuses the user.
I of course put a loop in, where Swing GUI regularly asks if Thread.isAlive (And sleeps some time to ask again), but this loop completely blocks Swing GUI.
Ideally, I would like to get a notification or an event that the thread has stopped.
Just like all the other events, Swing processes:-) .
What is the proper way to set it up?
Have a look at the SwingWorker. It is designed to perform tasks on the background as the result of a Swing event such a button press. It has hooks to listen for when the task finishes.
use a boolean flag 'done' private field. initialize done=false; when your thread run() method is complete set done=true inside thread run() method.
monitoring the value of the flag 'done' will tell you when your thread has finished.
I have a non-GUI thread that starts a JFrame using
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
cardReadPunchGUI = new IBM1622GUI(); // instantiate
cardReadPunchGUI.setVisible(true);
}
});
Part of IBM1622GUI's constructor instantiates a "model" for itself, which my non-GUI thread needs access to:
cardReadPunch = IBM1622GUI.getModel();
What is the correct way for my non-GUI thread to synchronize with the new GUI that's been "invoked later"? (Without synchronization, of course, IBM1622GUI.getModel() just tends to return null.)
Use
javax.swing.SwingUtilities.invokeAndWait(Runnable doRun);
instead.
Causes doRun.run() to be executed synchronously on the AWT event
dispatching thread. This call blocks until all pending AWT events have
been processed and (then) doRun.run() returns.
Id suggest you share an CountDownLatch initialized to 1 with both both the non-GUI and GUI threads.
The non GUI thread when it starts will call latch.await() which will put it in a blocked state.
The GUI thread will call latch.countDown() when it finishes its initialization after which the non-GUI thread will exit from the await call and both threads are synchronized.
Well, if you have access to it you could always move that particular logic outside of the Swing thread and onto the thread that calls invokeLater. There's nothing unsafe about doing what you're doing there off of the Swing thread, assuming the constructor for IBM622GUI is well behaved.
Other than that, you could make use of various other mechanisms.
You could use invokeAndWait, as cgull beat me to saying.
You could have the runnable set the value of a Future instead of a direct reference, and block on the main thread by calling the future's get method.
You could have a CountDownLatch with a starting count of 1 which you await() on your main thread, and countDown() from the Swing thread.
There are many, many utilities to help with synchronization.
Typically you pass parameters to the Thread. Run the logic in the background. And then post back any modifications you need to do to any of those objects, or UI elements on the UI thread using SwingUtilities.invokeLater(). Typically I create a simple a utility that allows me to specify what should run on the background thread, and what should run on the UI thread. SwingWorker is something you could use although I find it extremely painful to use. Something simple like this:
new AsyncThread<Param,T>() {
public T executeInBackground( Param param ) {
// do something long running
T result = // do something long running;
return T;
}
public void executeOnUI( T result ) {
// update the UI here, or modify the model, etc.
}
}.execute( param );
AsyncThread would execute the executeInBackground() method on another thread. Then internally it would post back to UI thread using SwingUtilities.invokeLater(). Then executeOnUI would run on the UI thread. The execute() method could create a thread to run in background, handle exceptions, etc.
I'd let the GUI possibly kick off the thread, and let the GUI pass it's model, or whatever part it needs, to the thread. Instead of the other way around. That way you can have the UI give feedback about that background thread that's running. But, you can't let the background thread touch (write/modify/change) members of that model that the UI thread would be reading/writing too at the same time. So if you plan on modifying the model in response to the background thread, post it back to the UI thread to be safe.
I have about 4 threads. One thread keeps checking some data that the other thread is updating. The others are doing some processing in the background. All have been started at this point.
My question is when the checking thread sees that the data has not been updated yet I currently sleep for a little bit but is there any way for me to tell the system to back to executing the thread that does the updating?
That or is there any way I can put something like a listener on the data(a String) and once its updated an event will fire that will do what it needs to do?
I tried using yield() and it seemed to just keep returning to the thread I called yield() from.
Thanks
This kind of simple notification is what Object.wait() and Object.notify() are intended for.
In your updater thread, you have
void updateData() {
synchronized (theData) {
theData.doSomeUpdate();
theData.notifyAll(); // tell other threads of a change
}
}
And then in your checking thread, have
void waitForUpdates() {
synchronized (theData) {
while (notCancelled) {
theData.wait(); // wait for notification
handleUpdate(theData);
}
}
}
Don't use Thread.sleep() since you can't really wake up the thread, unless you interrupt it, and that's a little nasty. Instead, use the wait/notify process above.
You can also look at passing notifications via an explicit BlockingQueue that is shared between the threads. The updater thread puts events in the queue, and the checker thread uses take() to fetch update events from the queue, waiting if there are no updates in the queue.
The difference with this scheme is that the updater thread can pass specific information about what has changed, rather than just saying "something changed", as is the case with wait/notify.
Also, the thread is notified of each update explicitly, so no updates are missed. It's also more flexible than wait/notify, since notification of updates does not require a lock on the data.
You cannot force a given thread to run. You can, however, put your checking thread to sleep and have your producing thread notify it when data is ready.
This is a classic "producer/consumer" problem, and java.lang.Object has methods to help you implement this (wait/notify/notifyAll). For higher level constructs, check out java.util.concurrent
You should consider wait() and notify().
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.