public static void moveTo(Coordinate destination) {
changeState(State.NAVIGATION);
controlPnl.addRemote(Remote.createRemote(remoteType.NAVIGATION));
dmc.moveTo(destination);
changeState(State.IMMEDIATE);
controlPnl.addRemote(Remote.createRemote(remoteType.IMMEDIATE));
}
In this code, the addRemote method updates the controlPnl GUI with new buttons. The dmc.moveTo method has up to two Thread.sleep calls in it, and I think that they are being called before the controlPnl GUI is being updated. I've commented out the two method calls after dmc.moveTo which change the GUI back to what it was before the call, and the controlPnl doesn't finish updating until moveTo finishes executing. What I need is for the GUI to finish updating before the moveTo method starts executing and puts the Thread to sleep. Is there any way that I could accomplish this in Java 6?
In case it matters, the moveTo method moves a LEGO Mindstorm robot to a specified point on a path defined by the user. The GUI that is being updated provides Swing components (JButtons and JRadioButtons) for the user to control the robot with while it's navigating. The addRemote method changes the set of Swing components for the user to use, and the moveTo method sends commands to the robot to actually execute the movement (by telling its motors to move, sleeping for the correct amount of time, then telling its motors to stop moving). I'm using a state machine pattern, and this method is part of the controller which handles events from the UIs.
You have a single GUI thread. Don't use it to call other things; if you do, those things have to complete before anything else is going to happen in your GUI.
At the very least you would want to start a new thread to perform your dmc.moveTo(destination). More than likely this isn't the only place you're doing this, and probably want an Executor set up to perform these tasks.
Without knowing more about your code (especially since you're using a static method) I can't comment on how you would want to set up the Executor but the simplest example of using a Thread would be:
public static void moveTo(final Coordinate destination) {
changeState(State.NAVIGATION);
controlPnl.addRemote(Remote.createRemote(remoteType.NAVIGATION));
new Thread(new Runnable() {
public void run() {
dmc.moveTo(destination);
changeState(State.IMMEDIATE);
controlPnl.addRemote(Remote.createRemote(remoteType.IMMEDIATE));
}
}).start();
}
This creates a new Thread that executes your (anonymous) Runnable which performs your moveTo(). Note this is far less efficient than having an Executor that is ready to run your task; it has to create a new Thread every time. However, if that's not an issue in terms of the performance you need then it's perfectly fine. Also note that because I'm referencing destination directly inside the anonymous inner class, it has to be declared final when passed into your method.
Since your moveTo takes a long time you should not execute it on the main event handling thread. Instead, have moveTo update the GUI and start the actual movement in a separate thread. Once the movement is complete, use SwingUtilities.invokeLater to do the second set of GUI updates.
private static ExecutorService executor = Executors.newCachedThreadPool();
public static void moveTo(final Coordinate destination) {
changeState(State.NAVIGATION);
controlPnl.addRemote(Remote.createRemote(remoteType.NAVIGATION));
executor.execute(new Runnable() {
public void run() {
dmc.moveTo(destination);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
changeState(State.IMMEDIATE);
controlPnl.addRemote(Remote.createRemote(remoteType.IMMEDIATE));
}
});
}
});
}
This way moveTo does the initial set of GUI updates and then returns immediately, freeing the event loop to keep the GUI responsive, but the second changeState is delayed until the dmc.moveTo is complete.
(it may make more sense to factor this stuff out into separate methods rather than using the Runnable-in-a-Runnable anonymous classes)
Related
I am having some major problems with swing's Thread model at the moment. AFAIK Swing defines 3 different Threads:
initial Threads: Here the program starts aka main methods, where the GUI will be started with some init() methods
Event dispatch Thread: The main thread for the GUI. Every bit of initialization of the GUI, updating the GUI etc. belongs here in this single thread
Worker Thread: for some background stuff of heavy weight tasks
Example:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// init gui here
}
});
}
This is a simple example in where the main method is the initial Thread, where the program starts and we invoke a new Thread (the Event dispatch Thread) where our GUI will be started.
Is this correct?
Now to my problem:
I am writing a Swing program, that connects to two different servers and visually dif's them. Therefore i have 2x Connection connection = ...
The first connection object to the "left" server exists within the initial main Thread, because the program will be executed within the environment of one of the servers => connection object is predefined by the environment and exists and the start of main(). The second connection object will be built manually within the program.
The problem now is that i use invokeLater() to shift every bit of GUI code to the Event dispatch Thread. Because i use a GUI to let the User select the credentials for the 2nd Server the connection code for the "right" server lies within the GUI and therefore in the Event dispatch Thread. However i do need both connection objects in one Thread because at one point i have to work with both objects at the same time.
Example:
public void run() {
// Left connection object is predefined and named "contect" here
// Right connection objects is created here using a GUI
connection = new ConnectionDialog().getConnection();
Project[] projects = connection.getProjects();
ProjectDialog pd = new ProjectDialog(Diff.this, projects);
otherProject = pd.getSelectedProject();
if (otherProject == null) {
return;
}
this.leftStore = (TemplateStoreRoot) context.requireSpecialist(StoreAgent.TYPE).getStore(Store.Type.TEMPLATESTORE);
this.rightStore = otherProject.getUserService().getTemplateStore();
this.leftSets = context.requireSpecialist(ProjectAgent.TYPE).getTemplateSets();
this.rightSets = otherProject.getUserService().getProject().getTemplateSets();
this.init();
this.setEnabled(true);
this.setVisible(true);
}
What the hell can i do to make this work? Am i doing it wrong by shifting every GUI code to the event dispatch Thread? The docu says i have to do so.
Thanks!
You must be creating a Frame to hold your UI right? Subclass JFrame, add your own constructor and pass the first connection object as a parameter. You can save it in your frame object and use it within it.
That said, you are not expected to do any lengthy calculations, waiting for network data etc. in the UI thread, if you want your UI to be responsive.
Apparently all Eclipse/SWT has in the way of managing the busy mouse indicator is
BusyIndicator.showWhile(Runnable synchronousStuffToDo)
However, I have a fundamentally event-oriented project where "stuff to do" doesn't happen within a sequential line of execution: an action gets ordered and a continuation-callback is provided to the execution manager. Therefore I have nothing meaningful to put into that synchronousStuffToDo runnable.
Is there another, however low-level and clumsy, but platform-independent way of manipulating the busy indicator asynchronously, which means two separate method calls, "activate it" and "deactivate it"?
I should add ProgressMonitorDialog to this question because it appears to suffer from the same problem. Yes, within the ProgressMonitorDialog#run method an inner event loop will be spinned, but SWT event loop is just one of my execution managers, so the chain will still be broken. Apparently without this class I can't even show a progress monitor except if I reimplement from lower-level primitives.
There is no way you can manipulate the Cursor using the BusyIndicator class.
You can invoke the below util method to show a Busy Icon while running your job on a background Thread
public static void imBusy(final boolean busy){
Display.getDefault().asyncExec(new Runnable()
{
#Override
public void run()
{
Shell shell = Display.getDefault().getActiveShell();
if(busy){ //show Busy Cursor
Cursor cursor = Display.getDefault().getSystemCursor(SWT.CURSOR_WAIT);
shell.setCursor(cursor);
}else{
shell.setCursor(null);
}
}
});
}
Your runnable should wait for the task completion. E.g. (code written in browser, will not compile - I'm ignoring exceptions):
final Object condition = new Object();
BusyIndicator.showWhile(new Runnable() {
public void run() {
synchronized(condition) {
while (!isMyTaskDoneFlag()) {
condition.wait();
}
}
}
});
doTask(new MyTask() {
public void perform() {
try {
// Task logic
...
} finally {
// When done
setMyTaskDoneFlag();
synchronized(condition) {
condition.notify();
}
}
}
});
Make sure all code paths in your tasks do not forget to unblock the runnable. Pretty much the same approach can be used with progress monitors - you may wake your runnable to update progress monitor value.
Note: You need to make sure the waiting runnable is not executed on SWT thread (e.g. set fork to true if running in progress monitor) or else your application will become unresponsive.
I found a solution (which I don't particularly like, but it works) in an older SWT application I'm working on now. It uses BusyIndicator#showWhile, and the synchronous stuff it does inside is:
Start the asynch task in a background thread
Loop waiting for the background thread to finish up while at the same time spinning the
SWT event loop explicitly:
while (!taskDone){
if (!display.readAndDispatch() && !shell.isDisposed()) {
display.sleep();
}
taskDone = //check for task progress
//update something on the main window status bar
}
I'm trying to convert this to something cleaner (along the lines of what Marko suggested):
Set the busy icon
Submit background task
Unset the busy icon
but I'm not sure what would be best for updating the status bar (background tasks are actually remote calls so their thread is blocked until they finish up). I'm thinking of having a dedicated thread that detects when background jobs are running and update the status bar accordingly (the update is just an unfolding dotted line, nothing task specific), but using a thread just for this seems a bit of a waste.
I have been messing around a bit with the runOnUiThread method. And if I simply make a method in my activity:
public void Test()
{
runOnUiThread(new Runnable()
{
public void run()
{
Log.v("mainActivity", "test");
}
});
}
I noticed that this runnable only runs once. However, this is not a problem. What I was wondering is if I have completely missed something and it does something in the background that would cause a frame rate drop when I have executed the method a couple times.
This is the full body from Activity.runOnUiThread(Runnable):
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
The method body is still executed in your background thread, and mHandler of class android.os.Handler implements an internal queue for Runnables posted to it, so unless you're doing blocking work in the Runnable (which is a big no-no on the UI Thread) or calling this method upwards of a thousand times in a short period, you should not see any difference.
Now, if you were calling Handler.postAtFrontOfQueue(Runnable), then there'd be an issue, because your Runnable is essentially "cutting in line". In this case, that would likely cause a stutter, because your Runnable is being executed instead of any UI updates that needed to take place (like scrolling).
Note that you only need to run UI updates on the UI thread, like calling any methods on a View (thus the name "UI Thread" and why this method exists) or any operation where the documentation explicitly states that it needs to be run on the UI thread. Otherwise, if you're already on a background thread, there's no real reason to leave it.
It's unlikely that it would cause any significant interruption to your UI process, but there's really no point in running it on the UI thread.
If you are doing any significant amount of work, you should make sure that you do not do it on the UI thread.
I'm writing a chess program in java. So far things are coming along fine but I do have a problem with updating my UI.
Here's a snippet of code from class ChessBoard which extends JPanel. This is called when a user tries to make a move:
if ( isLegalMove( aMove ) ) { // If the move's legal
makeMove( aMove ); // Make that move
select = null; // Reset some info
drag = null;
toggleTurn(); // Change turns
generateMoves( 0 ); // Get legal moves for CPU
repaint(); // Redraw board
thread.run(); // Run chess algorithm
}
The thread is calling "run" on my instance of ChessBoard. The algorithm that finds the move can take several seconds to decide on a move.
I would like for my UI to update to reflect the user's move and then run the algorithm. That's why I run the algorithm on a separate thread. But my UI is not being updated until the computer also makes a move.
So if the user clicks a space to send a piece there, the screen freezes and then all of a sudden the piece has moved but the computer has moved also and it is again the player's turn.
Any help will be greatly appreciated.
thread.run() is going to execute the code in the thread's run method on the current thread. You want thread.start().
Relevant JavaDoc
The repaint method doesn't actually repaint immediately. It basically tells the JPanel that it ought to repaint itself soon. Then you go ahead on the same thread and calculate the AI's move, which will freeze the window because Swing isn't multi-threaded.
First, threads are not re-entrant (I'll explain that in a moment).
thread.run() is not causing the thread to execute in a separate thread, it's just call the run method of the thread (within the current Threads context.
What you need to do is set up a condition loop within your Thread that you can trigger in order to execute the logic you need.
public class ChessThread extends Thread { // I prefer Runnable, that's me
protected static final Object NEXT_MOVE_LOCK = Object();
public ChessThread() {
setDaemon(true); // This will allow the JVM to exit without the need to terminate the thread...
}
public void doNextMove() {
// Notify the "wait" that we want to continue calculating the next move
synchronized (NEXT_MOVE_LOCK) {
NEXT_MOVE_LOCK.notify();
}
}
public void run() {
while (true) {
// Wait for the "next move" request
synchronized (NEXT_MOVE_LOCK) {
try {
NEXT_MOVE_LOCK.wait();
} catch (InterruptedException exp) {
}
}
// Calculate the next move...
}
}
}
Now, Threads are non-reentrant, this means that once the run method has complete, that instance of the Thread can not be restarted.
Hence using thread.start() more then once will not work (can't remember if it throws an exception or not) (hence the reason I prefer Runnable)
So. What you want to do, is start the Thread when your program loads and when you need to, call thread.doNextMove() to cause it calculate the what ever it is you need.
Now, also remember, Swing is not Thread safe. That is, you should NEVER update the UI from any Thread other than the Event Dispatching Thread (or EDT)
You might also want to have a read through Concurrency in Swing
Oh and Concurrency in Java
Please explain invokeAndWait() method in SwingUtilities.I am unable to understand this.
Explain it very clearly. It would be of great help if you try out with an example.
Edited to add #noob's expansion of the question:
What's not clear about this?
Here's a modified usage example:
import javax.swing.SwingUtilities;
public class InvokeAndWaitStuff
{
public static void main(String[] args)
{
final Runnable doHelloWorld = new Runnable() {
public void run() {
System.out.println("Hello World on " + Thread.currentThread());
}
};
Thread appThread = new Thread() {
public void run() {
try {
SwingUtilities.invokeAndWait(doHelloWorld);
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println("Finished on " + Thread.currentThread());
}
};
appThread.start();
}
}
Output:
Hello World on Thread[AWT-EventQueue-0,6,main]
Finished on Thread[Thread-0,5,main]
And why is this important?:
Causes doHelloWorld.run() to be
executed synchronously on the AWT
event dispatching thread. This call
blocks until all pending AWT events
have been processed and (then)
doHelloWorld.run() returns. This
method should be used when an
application thread needs to update the
GUI.
As far as I can tell, this is basically a bottleneck that forces GUI updates to be executed synchronously by a single thread, rather than asynchronously by multiple threads, which can potentially be unsafe.
To understand what invokeAndWait() does, you first need to understand the event/thread model of Swing.
Basically, everything that affects the GUI in any way must happen on a single thread. This is because experience shows that a multi-threaded GUI is impossible to get right.
In Swing, this special GUI thread is called the Event Dispatch Thread, or EDT. It is started as soon as a Swing top-level component is displayed, and it's bascially a worker thread that has a FIFO queue of event objects that it executes one after another.
When a Swing GUI needs to be drawn or updated, the JRE places an event on the EDT queue. User actions that cause listeners to be called start as events on the EDT queue. And (this is this is the important part) everything your program does that changes the GUI (like registering listeners, adding/removing GUI components or changing model data that the GUI displays) must be placed in the EDT queue, or the GUI can get corrupted.
And now for the finish: invokeAndWait() places the Runnable you pass to it into the EDT event queue and waits until the EDT has executed it. This should be used when a non-GUI thread needs to do something that affects the GUI, but also needs to wait until it is actually done before it can continue. If you just want to do something that affects the GUI but do not care when it is finished, you should instead use invokeLater().
I had a similar problem in a JTable. The program was blocked somewhere in "scrollRectToVisible" method. I have replaced the call by wrapping it in an invokeLater call.
The invokeAndWait did not resolve my block problem.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
table.scrollRectToVisible(r);
}
});