Java Swing making the thread wait once - java

I'm trying to make my GUI wait for 2 seconds after a recent update in the graphics. It means that after I use:
boardLogo.repaint();
boardLogo.revalidate();
I want the GUI to wait before making further computations and then paint them again.
The code:
SwingUtilities.invokeLater(new Runnable() {
#SuppressWarnings("rawtypes")
#Override
public void run() {
SwingWorker swingWorkerExample = new SwingWorker(){
#Override
protected Object doInBackground() throws Exception {
return null;
}
protected void done(){
try {
Thread.sleep(2000); //wait 2 seconds.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
swingWorkerExample.execute();
}
});
//.... more code here
boardLogo.repaint();
boardLogo.revalidate();
But when I run it - first it executes the last two lines, then waits for 2 seconds...
To be honest, my knowledge about Threads and Java Swing is not the best (especially when it comes to understanding swing worker, which I've tried to read about from Oracle site), so I would appreciate it if the answer will be detailed.
Thanks!

when I run it - first it executes the last two lines, then waits for 2 seconds ... my knowledge about Threads and Java Swing is not the best.
You say, it executes the last two lines. Ever stop to wonder what it is?
It is a thread. Threads are what execute code in a Java program, and every line that gets executed is executed by some thread.
When your code calls invokeLater(), it is submitting a task (i.e., a piece of code) to be executed by Swing's event dispatch thread (EDT); and when your code calls swingWorker.execute() it is submitting a task to be performed by one of Swing's background threads.
The whole point of having more than one thread in a program is that they can be doing different things at the same time.
In your case, you've got the EDT sleeping for two seconds while, at the same time, some other thread is calling boardLogo.repaint(); and boardLogo.revalidate();
There's a couple of important things to know about Swing and multi-threading:
All of your event handlers will be run by the EDT.
An event handler should never do anything that takes more than a small fraction of a second, because your application will not be able to respond to any other events (i.e., it will appear to be "hung") until the handler returns.
No other thread is allowed to interact with any of Swing's GUI components.
One important use-case for invokeLater() is, it's how code running in the background thread can communicate with GUI components. invokeLater() submits a task (i.e., a piece of code) that will be run in the EDT.
The main use-case for SwingWorker is pretty much the opposite of that: It's how an event handler, running in the EDT, can kick off a task that is going to take more than a small fraction of a second to complete.
You can learn about this stuff by working your way through the Swing Concurrency tutorial: https://docs.oracle.com/javase/tutorial/uiswing/concurrency/

Related

Swing: Running code immediately vs invokeLater

I'm currently working with a thread control class someone else wrote. It is used for a java swing application. I have two methods, but I am confused as to why I am getting different behaviors from both. From what I know and read about the event dispatcher thread and Swing, there should be no difference in the two methods below. Apparently, this is not true.
//If this is the AWT Event Processing thread then run the code immediately,
//otherwise schedule it for later processing
public static void runWithEventThread(Runnable r)
{
if (EventQueue.isDispatchThread())
{
r.run();
}
else
{
EventQueue.invokeLater(r);
}
}
//Schedule the runnable for later processing by the AWT Event Queue
public static void runLaterWithEventThread(Runnable r)
{
EventQueue.invokeLater(r);
}
When using runWithEventThread() to display popups while updating GUI (new buttons/repainting), I found that the GUI would mess up sometimes. However when using runLaterWithEventThread(), it was all fine, no issues.
Only problem is that when using runLaterWithEventThread() I found that when I had multiple popups that would be displayed one after the other (after OK clicked) all popups were displayed at once.
From what I understand, both the methods should be doing the same thing. Can someone please explain what is going on
If your first method is executed from the event thread, it MAY act differently than the second method: If there are any events currently waiting on the event thread, those events will be processed BEFORE your run() method is executed if you use the second method, but if you use the first method, your run() method will be executed immediately, and any existing events on the queue will be run AFTER your run() method finishes.

Multi-threading with Swing

I am trying to write a multi-thread program with Swing. Essentially how the program works is that when it runs it will have a robot(represented by a circle in screenshot) that is wondering around in a field. This robot should be controlled by a thread of it's own. The program has a button "Launch Robot" that will create another robot on the field(upto a max of say 10). Right now I have the basics of the program, but it all runs under one thread. I can launch as many robots as I want but they all run under a single thread. But I want that whenever I click "launch Robot" an independent thread be created and control that robot. This is how the program looks right now:
The UML diagram for the program is as following:
Since its a bit long I won't post the whole program. But the method that starts and updates the robots(currently controlling only one robot on the field) is as follows:
public void gameStart(){
Thread gameThread = new Thread(){
public void run(){
while(true){
//execute one time step for the game
gameUpdate();
//refresh screen
repaint();
//give other threads time
try{
Thread.sleep(1000/UPDATE_RATE);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
};
gameThread.start();
}
My question is how can I achieve multi-threading for such a scenario? I know the basics of SwingWorker, but since I haven't done any multi-threading, I have no idea on how to make several threads work and be updated by one thread(update position of robots that are controlled by threads).
EDIT: Just to make my point, this is a project that I am working on. It's not about if multi-threading makes sense in this scenario or not.
Create a RobotModel that contains a Collection<Robot> and defines their interaction. Iterate the model in the doInBackground() implementation of a SwingWorker. Invoke publish() as meaningful events arise, and process() updates to the RobotWorld view by querying the model. As discussed here, there should be no drawing in the model and no interaction logic in the view. A single worker should suffice for a moderately complex model, but you can synchronize multiple workers as shown here.
A good option to achieve this is to use ScheduledThreadPoolExecutor.
Instantiate the thread pool via:
ScheduledThreadPoolExecutor threadsPool = new ScheduledThreadPoolExecutor(size);
To create a new Robot Thread, use:
threadsPool.submit(new Runnable() {
#Override
public void run() {
launchRobot();
}
});
This way, each invocation will instantiate a new Thread.
You can set the limit of the total number of allowed Thread via the "size" argument.
You can also pass a result after each thread completes using:
public <T> Future<T> submit(Runnable task, T result)
If you want less detail, you could let Java do the work for you with the following convenience API:
Executors.newCachedThreadPool() (unbounded thread pool, with automatic thread reclamation) or:
Executors.newFixedThreadPool(int) (fixed size thread pool)
Remember us, Executor. Remember what was done here today. And may Adun watch over you
This robot should be controlled by a thread of it's own.
Why?
IMO, the most important way to describe any thread is to say what it waits for. In an internet server, an accept thread waits for incoming connections from new clients, and a client thread waits for additional commands from a single client. In a program that performs massive parallel computations, a worker thread waits for tasks to be performed. In a GUI program, the event dispatch thread waits for keyboard and mouse events. Etc., etc.
What will your robot thread wait for?
If it waits for time to pass (i.e., if it calls Thread.sleep()), then your GUI framework probably already has a timer thread that does that, and you might want to consider using it. (In Swing, you would use the javax.swing.Timer class to submit new timed tasks.)

using sleep() for a single thread

I am fairly new to java, and am starting to get into using different threads in order to use wait() or sleep() on one part of my code and have the others still run.
For this project, I am using JFrame with the javax.swing.* and java.awt.* imports. What I am trying to do is have one of the threads (in my code it is the main, starting thread) allow the player to choose a space on the tic tac toe board, and when they click it, it will change icons, and then the AI will wait for 1 second before playing back from the second thread that I created.
Unfortunately, whenever I call ait.sleep(1000) (ait is my thread name) both threads wait for 1 second before finishing their execution. Can anyone tell me why sleeping one thread is stopping my whole execution?
Can anyone tell me why sleeping one thread is stopping my whole
execution
to better explain your Swing GUI is created on its own special thread separate from that which main() and other code will run in, this is done via creating your Swing components in the SwingUtilities.invokeXXX block (even if you have not done this your GUI will be run on a single thread called the initial thread) . Now if you simply call sleep while on Event Dispatch Thread (or for that matter on the same Thread) it will wait for the call to Thread.sleep to finish. Now because all Swing events are processed on EDT we pause its execution by calling sleep(..) thus pausing the UI events from being processed and therefore GUI is frozen (until sleep(..) returns).
You should not use Thread.sleep(..) on Event Dispatch Thread (or any Thread where sleep will cuase unwanted execution blocking), as this will cause the UI to seem frozen.
Here is a nice example which demonstrates exactly, this unwanted behavior caused by invoking Thread.sleep(..) on GUI's EDT.
Rather use:
Swing Timer for example:
int delay=1000;// wait for second
Timer timer = new Timer(delay, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
//action that you want performed
}
});
//timer.setRepeats(false);//the timer should only go off once
timer.start();
Swing Worker
or if no Swing components are being created/modified:
TimerTask
Thread, you would then use Thread.sleep(int milis) (but thats last option in any case IMO)
UPDATE
Swing Timer/SwingWorker was only added in Java 1.6, however, TimerTask and Thread have been around for alot longer sine Java 1.3 and JDK 1 repsectively, thus you could even use either of the 2 above methods and wrap calls that create/manipulate Swing components in SwingUtilities/EventQueue#invokeXX block; thats the way things used to be done :P
Thread.sleep is a static method. Invocations of it via the reference of any given Thread is simply a form of convenience.
As a result, any invocation of sleep is really calling sleep on the current Thread, which I suspect is the Event Thread in your case. Sleeping/blocking on the Event Thread will give the appearance of being locked up.
If you want the ait thread to sleep, then code that thread to sleep. Designs where one thread "reaches into" another and pushes it around at a low level are fundamentally broken. You write the code for every thread, so write it to do what you want it to do in the first place so you'll find no need to reach into it from the outside.
Which makes more sense, for the person in the kitchen to know how to cook breakfast or the person in the bedroom to yell down and direct them to perform each step of making breakfast? Sure, you might tell them to make breakfast. But you definitely don't direct each step at a low level.
Thread.sleep is a static method which causes the currently executing thread to sleep for the specified amount of time. Java syntax allows you to call a static method via a variable, but the compiler simply uses the compile-time type of that variable to determine which method to call, i.e.
Thread ait = null;
ait.sleep(1000); // calls Thread.sleep(1000), causing current thread to sleep.
// In particular, does *not* NPE
You also mentioned wait() - while this is an instance method rather than a static it still causes the current thread to do the waiting (ait.wait(1000) would cause the current thread to wait for up to 1 second or until another thread calls ait.notifyAll()).
There is a Thread.suspend() and its counterpart resume() that were introduced in the very early days of Java to allow one thread to control another, but they were deprecated soon after as they are inherently deadlock-prone. The recommended pattern if you want one thread to "control" another is to do it co-operatively, i.e. have some kind of shared flag that thread A sets and thread B reads, and have B send itself to sleep according to the flag:
volatile boolean threadBShouldRun = true;
// Thread B
while(true) {
if(threadBShouldRun) {
// do some stuff
} else {
Thread.sleep(1000);
}
}
// Thread A
if(someCondition) {
threadBShouldRun = false;
}
but it's generally easier and less error-prone to make use of the facilities that exist in the java.util.concurrent package. Doing multi-threading right is much harder than it appears on the surface.

Multithreading and UI behavior

I have a java app in which I use a thread. My thread runs every 20 seconds but, when it runs it kind of blocks the UI ... i. e. whenever the thread is running and the user clicks on button on anything on UI it doesnt respond sometimes.
Could anyone tell me a solution to this problem.
in java Swing, any change made to the state of the UI should be done in a single pre-existing thread called the EDT (event-dispatcher thread).
if that's not the case, you typically experience weird glitches / freezes. one of the most common symptom is that part of the UI becomes gray (except since java 1.6, where the ui is still painted like before, but unresponsive).
the good way to go is to use a dedicated method to queue your changes to the UI in the EDT :
SwingUtilities.invokeLater(Runnable toRunInEDT);
note that if you call invokeLater, the runnable is executed after all currently queued event have been dispatched. that means that the next line of code could be executed before the code in the runnable. there is a synchronous version as well (which should not be executed from the EDT):
SwingUtilities.invokeAndWait(Runnable toRunInEDT);
Some additional tips, on top of what edralzar said:
You can use the convenience method SwingUtilities.isEventDispatchThread() to check if code is in fact running on the event dispatch thread. And, like edralzar said, any code that creates GUI components, modifies the state of GUI components or reads the state of GUI components should run on the Event Dispatch Thread.
Another thing to consider, however, is that code running on the EDT should be able to execute rather quickly. So you cannot just solve things by running everything on the event dispatch thread. If you do the following, your GUI will be frozen for five seconds:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
try{
Thread.currentThread().sleep(5000);
}catch(InterruptedException e){
//Ignored in this example
}
}
});
Why is it frozen? Because all GUI events and GUI updates are performed on the EDT, and if the EDT sleeps for 5000 miliseconds, no GUI updates can be performed during that time.
This article might be an interesting read.
Sounds to me like the thread you're referring to (that runs every 20 seconds) is also the thread that governs the UI.
The solution is to separate the two processes onto different threads.

Updating Swing component from another thread with invokeLater or SwingWorker

I'm developing a small app, which would have Swing GUI. App is doing IO task in another thread, when that thread finishes GUI should be updated acordingly to reflect thread's operation result. Class running in a (worker, non-GUI) has object passed to it in contructor which would be used for updating GUI, so I don't need to put GUI stuff in a non-GUI class, but rather pass object for updating GUI to that class.
As I understand form reading here, (thread/swing) safe options for updating (changing) Swing GUI would be to use javax.swing.SwingUtilities.invokeLater(), javax.swing.SwingUtilities.invokeLaterWait() and/or javax.swing.SwingWorker() which basically are doing the same thing.
This all threading issue with Swing is a little confusing for me, and yet I need to use threads to do anything meaningful in GUI apps and not hung GUI while processing in EDT, so what interests me for now is this:
Are invokeLater and invokeLaterWait like sending message to EDT and waiting for it do it when it finishes processing messages that were before that call?
is it correct from Swing thread safety aspect, to do something like this:
interface IUPDATEGUI {
public void update();
}
// in EDT/where I can access components directly
class UpdateJList implements IUPDATEGUI {
public void update() {
// update JList...
someJList.revalidate();
someJList.repain();
}
}
class FileOperations implements Runnable {
private IUPDATEGUI upObj;
List<File> result = new ArrayList<File>; // upObject is accessing this
public void FileOperations(IUPDATEGUI upObj) {
this.upObj = upObj;
}
private void someIOTask() {
// ...
// IO processing finished, result is in "result"
}
public void run() {
someIOTask();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
upObj.update(); // access result and update JList
}
}; );
}
}
In case this isn't correct then how should this be done?
If I could, I would prefer to use invokeLater instead of SwingWorker if possible, because I wouldn't need to change my whole class and it's somehow more neat/distinct me (like sending a message in Win32 apps).
Thanks in advance.
Using invokeLater() and invokeAndWait() passes the Runnable parameter into the queue awaiting execution in the EDT. So calling invokeLater() will cause the Runnable to execute in the EDT when the EDT is able to process the request. invokeAndWait() simply waits (in the calling thread) until this execution takes place.
Using SwingWorker is ideal if you want to do background tasks that notify the EDT either at the end of execution or in intermediate states. An example would be to pass the current progress of a process to a JProgressBar.
For your example it seems that SwingWorker is a better choice but if you don't want to change your code too much then calling invokeLater() when the process is done will be just fine.
I'd recommend not using the invokeAndWait until java 7. I found a spurious wake-up on this method that can cause really painful bugs. For me it led to some really rare and hard to debug null pointer exceptions.
http://bugs.sun.com/view_bug.do?bug_id=6852111
It's fixed as of java 7 b77.
invokeLater is fine. This puts the call into the AWT event queue, so that it will get executed in the EDT in due course. Your program will continue running, and does not wait for your callable to get called.

Categories