I am building a java application and i have implemented custom listeners and events. The problem now is that there are many events and listeners and the application GUI thread is being blocked while the listeners process the events. Can this be solved using event dispatch thread? If so how?
The code for listeners:
public class ProjectChangeObserver
{
private List<ProjectChangeListener> listeners = new ArrayList<ProjectChangeListener>();
public void addProjectChangeListener(ProjectChangeListener l)
{
listeners.add(l);
}
public void removeProjectChangeListener(ProjectChangeListener l)
{
listeners.remove(l);
}
public void removeAllProjectChangeListeners()
{
listeners.clear();
}
public void fireProjectChange(ProjectChangeEvent e)
{
if(listeners.size() > 0)
{
ArrayList<ProjectChangeListener> safeCopy = new ArrayList<ProjectChangeListener>(listeners);
for (ProjectChangeListener cl : safeCopy ) {
cl.onProjectChange(e);
}
}
}
}
One of the features of Swing is that it is single-threaded.
However, there is nothing stopping you from spawning your own threads to do background processing. As long as you only make calls to revalidate() or repaint() then all the drawing will still be handled in the Swing thread.
(Remember that if you are going to be spawning other threads to do background work then ensure that your variables are declared volatile if you expect the Swing thread to see the same values as in your threads. Or pass the information back through another listener.)
If you are intending to do the painting itself (e.g. of custom components) in separate threads, then it is either not possible or very strongly discouraged depending on the situation. (Some exotic situations may permit multi-CPU generation of a scene in a custom thread-safe buffering class, but you're unlikely to be doing that).
If you are finding that your Listeners are CPU/network intensive, then you might want to think about the architecture of who is doing the majority of the shouting and who is doing the listening. I always try to minimise the amount of shouting in my "view" code so that it simply responds to events.
Incidentally, I've found Project Lombok and its Beta sister Lombok PG to greatly reduce the boilerplate of implementing the Listener pattern with #ListenerSupport.
Quite to the contrary, this must be solved avoiding the Event Dispatch Thread ("GUI thread" is just another name for the same thing). You must use SwingWorker to start an asynchronous task in its own thread.
You should run separate threads for your events if you want to prevent UI blocking.
If you want to use a single thread for events then you can create the thread and you can pass commands to your event thread using a queue where you store your events.
But you should open async threads for your events if possible and you should make sure you refresh the UI whenever needed.
Related
I'm attempting to add a fancy InfiniteProgressPanel as a GlassPane for my big Swing program. However, it does not appear. It looks similar to this:
...
InfiniteProgressPanel glassPane = new InfiniteProgressPanel();
setGlassPane(glassPane);
...
glassPane.start();
doSomeStuff();
glassPane.stop();
...
I believe it is running in the same thread as the long process it is meant to cover up. I'll admit, I don't know nearly enough about threads, and I should probably figure out how to run that InfiniteProgressPanel GlassPane in a separate thread, and the long process in its own thread, too.
Be sure to:
Run all long running code in a background thread. This is a must.
Sounds great! How do I do so? Encapsulate all of the long-running code inside of an .invokeLater method? And should that be SwingUtilities.invokeLater or EventQueue.invokeLater? And what's the difference, anyway?
No, by using SwingUtilities.invokeLater(new MyRunnable) you're doing exactly the opposite -- you're guaranteeing that the long-running code will be called on the Swing event thread -- the exact opposite of what you want. Instead use a SwingWorker's doInBackground() method to run the long-running code. Regarding your second point, there's no difference whatsoever between SwingUtilities.invokeLater and EventQueue.invokeLater.
Make most all Swing calls on the Swing event thread, also a must.
Fantastic! Again, how do I do so? Same thing as above?
By using SwingUtilities.invokeLater(new MyRunnable) as noted above, or if you're using a SwingWorker then use its publish/process method pair as the SwingWorker tutorial will show you.
Call setVisible(true) on your glass pane since per the JRootPane API, all glasspanes are by default invisible.
Romain Guy's InfiniteProgressPanel doesn't seem to need a setVisible(true). It appears when the InfiniteProgressPanel.start() method is called.
I am not familiar with this, do you have a link?
Threads are different processes in the same program, per se.
In java, there are many different thread types, and the one you need for this job is SwingWorker.
The definition/use of this, from Oracle's docs, is:
When a Swing program needs to execute a long-running task, it usually uses one of the worker threads, also known as the background threads. Each task running on a worker thread is represented by an instance of javax.swing.SwingWorker. SwingWorker itself is an abstract class; you must define a subclass in order to create a SwingWorker object; anonymous inner classes are often useful for creating very simple SwingWorker objects.
As you can see, this is what you need; a background thread.
final InfiniteProgressPanel glassPane;
...
class GlassPaneHandler extends SwingWorker<String, Object> {
#Override
public String doInBackground() {
glassPane.start();
return setUpPaneAndStuff();
}
#Override
protected void done() {
try {
glassPane.stop();
} catch (Exception e) { } //ignore
}
private void setUpPaneAndStuff() {
//code
}
}
...
(new GlassPaneHandler()).execute(); //place this in your code where you want to initiate the pane
for more see:http://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html
When you are updating a swing UI you need to do it in Swing's Event Thread. This includes creation of components or any sort of progress updates. You can do this via the SwingUtilities.invokeLater(Runnable) method.
Therefore, you should create the glasspane and show it via the invokeLater if in a background thread. Any progress updates to the glasspane from your long running process thread should be done via the invokeLater.
I'm trying to flash a Java graphic object by changing the color and calling the repaint() method. The color is only updating with the final change color call. Here is my code:
public void start() {
try {
Color origColor = node.getColor();
for (int i=0; i<noOfFlashes; i++) {
Manager.gui.getDrawGraph().changeNodeColor(node, Color.WHITE);
Thread.sleep(500);
Manager.gui.getDrawGraph().changeNodeColor(node, origColor);
Thread.sleep(500);
}
Manager.gui.getDrawGraph().changeNodeColor(node, Graph.VISITED_NODE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
and the change node color method is:
public void changeNodeColor(Node node, Color c) {
node.setColor(c);
repaint();
}
The change node color is in the same class as the paint component.
Any help would be much appreciated.
You need to use separate thread to manage your GUI event.
You can do this, using a SwingWorker, as suggested by Amine, or implement the Runnable interface, or extend the Thread class, developing the run() method, that is the task of your thread.
You can read this old question of SO : How do I use SwingWorker in Java?
A tutorial for SwingWorker : http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
A tutorial to make a Thread : http://docs.oracle.com/javase/tutorial/essential/concurrency/
The color is only updating with the final change color call.
If you don't use a separate thread, your gui will freezing until the method is completely executed, and you won't see the color change separated by Thread.sleep(500);.
UPDATE
In this link, in the paragraph Why does a Swing GUI freeze or lock up?, you can understand why a Java Swing GUI freezes, with the use of a single thread.
Check also this official link, in the paragraph Creating Threads, and this page, that returns:
Swing's single-thread rule says that Swing components can only be
accessed by a single thread. This rule applies to both gets and sets,
and the single thread is known as the event-dispatch thread.
The single-thread rule is a good match for UI components because they
tend to be used in a single-threaded way anyway, with most actions
being initiated by the user. Furthermore, building thread safe
components is difficult and tedious: it's a good thing not to be doing
if it can be avoided. But for all its benefits, the single-thread rule
has far-reaching implications.
Swing components will generally not comply with the single-thread rule
unless all their events are sent and received on the event-dispatch
thread. For example, property-change events should be sent on the
event-dispatch thread, and model-change events should be received on
the event-dispatch thread.
For model-based components such as JTable and JTree, the single-thread
rule implies that the model itself can only be accessed by the
event-dispatch thread. For this reason, the model's methods must
execute quickly and should never block, or the entire user interface
will be unresponsive.
I think that the sentences above are very useful to understand better the Swing package.
I report the suggestion of trashgod.
You can use the Timer class, from the javax.swing.Timer package. That is also a good alternative.
In this question, trashgod reports some examples of Timer.
Check here for a tutorial about Timer.
Based on what i understand from your code, I will probably recommend the use of SwingWorker.
I know you do not have any cost expensive code but you using SwingWorker, you will be able to update your GUI more easily.
I am not sure which framework you're using here... but you may need a repaint() just before the Thread.sleep(). Is there a Manager.gui.repaint() perhaps? (Sorry, complete guesswork here...)
Is there a way to block the execution on the EDT, with still having a vivid gui?
I noticed that JDialog/JOptionPane has something similar, when calling setVisible(true).
Why would i need this?
My Class should satisfy to following interface:
interface Quitable {
boolean quit();
}
My Class needs a implementation like this:
class MyApp implements Quitable {
ExecutorService executor = Executors.newCachedThreadPool();
// ...
public boolean quit() {
FuturTask<Boolean> futureTask = new FutureTask<Boolean>(saveJob);
executor.execute(futureTask);
// TODO: keep gui vivid
boolean saveResult = futureTask.get();
return saveResult;
}
// ...
}
I need to return the result of the save process (which may take some time and may fail). Or would you suggest another solution? Thanks for any ideas. ;)
Dialog causes the an event loop to be executed whilst it is blocking. There is a filter that allows certain events through such as repaint requests, invocation events and events to the dialog window. The API for this is not exposed.
There was a library (Foxtrot, IIRC), that used a hack on Dialog to expose this behaviour.
I would strongly suggest structuring your program in such a way that this is not required. It's a very procedural rather than event-driven organisation. So queue your task on another thread (possible a thread pool/executor service or GUI-like event-loop), and then update the GUI with java.awt.EventQueue.invokeLater.
JDialog does not block the execution of EDT, EDT ignores events except jDialog's event when it is opened as modal.
I do suggest you to show progressbar as modal, before calling quit method.
I have a swing application which stores a list of objects. When the users clicks a button,
I want to perform two operations on each object in the list, and then once that is complete, graph the results in a JPanel. I've been trying SwingWorker, Callable & Runnable to do the processing, but no matter what I do, while processing the list (which can take up to a few minutes, as it is IO bound), the GUI is locked up.
I have a feeling it's probably the way I'm calling the threads or something, or could it be to do with the graphing function? That isn't threaded as it is very quick.
I have to do the two processing stages in order too, so what is the best way to ensure the second one has waited on the first? I've used join(), and then
while(x.isAlive())
{
Thread.sleep(1000);
}
to try and ensure this, but I'm worried this could be the cause of my problem too.
I've been looking everywhere for some pointers, but since I can't find any I'm sure I'm doing something stupid here.
The problem is, your long running task is blocking the Thread that keeps the GUI responsive.
What you will need to do is put the long running task on another thread.
Some common ways of doing this are using Timers or a SwingWorker.
The Java tutorials have lots of information regarding these things in their lesson in concurrency.
To make sure the first task finishes before the second, just put them both on the same thread. That way you won't have to worry about keeping two different threads timed correctly.
Here is a sample implementation of a SwingWorkerFor your case:
public class YourTaskSwingWorkerSwingWorker extends SwingWorker<List<Object>, Void> {
private List<Object> list
public YourClassSwingWorker(List<Object> theOriginalList){
list = theOriginalList;
}
#Override
public List<Object> doInBackground() {
// Do the first opperation on the list
// Do the second opperation on the list
return list;
}
#Override
public void done() {
// Update the GUI with the updated list.
}
}
To use this code, when the event to modify the list is fired, create a new SwingWorker and tell it to start.
You are not returning the swing thread properly. I realize you are using callable/runnable but i'm guessing you are not doing it right (although you didn't post enough code to know for sure).
The basic structure would be:
swingMethod() { // Okay, this is a button callback, we now own the swing thread
Thread t=new Thread(new ActuallyDoStuff());
t.start();
}
public class ActuallyDoStuff() implements Runnable {
public void run() {
// this is where you actually do the work
}
}
This is just off the top of my head, but I'm guessing that you either aren't doing the thread.start and are instead calling the run method directly, or you are doing something else in the first method that locks it up (like thread.join). Neither of these would free up the swing thread. The first method MUST return quickly, the run() method can take as long as it wants.
If you are doing a thread.join in the first method, then the thread is NOT being returned to the system!
Edit: (Second edit actually)
I think to speak to the problem you are actually feeling--you might want to think more in terms of a model/view/controller system. The code you are writing is the controller (the view is generally considered to be the components on the screen--view/controller are usually very tightly bound).
When your controller gets the event, it should pass the work off to your model. The view is then out of the picture. It does not wait for the model, it's just done.
When your model is finished, it needs to then tell the controller to do something else. It does this through one of the invoke methods. This transfers control back to the controller and you go on your merry way. If you think about it this way, separating control and deliberately passing it back and forth doesn't feel so bulky, and it's actually very common to do it this way.
It sounds like the problem might be that you are waiting on the threads to finish from inside the GUI thread. Your GUI thread should not wait on these threads, instead you should have the worker threads invoke some method on the GUI thread that sets a flag. When both flags are set then you know both threads finished and you can do the graph.
I can't really speak to the swing threading model, but:
I have to do the two processing stages in order too, so what is the best way to ensure the second one has waited on the first?
For this kind of functionality, I'd suggest you create two worker threads, and embed a JMS broker. Deliver work to the two threads by passing messages into JMS queues that they read from. Your GUI thread is free to examine the queues to determine when work is happening and represent the state of play in your UI.
The solution to my problem was a mixture of jjnguy and Bill K's answers, so thanks very much for that guys. I needed to use threads within a SwingWorker like this:
public class Worker extends SwingWorker<Void, Void>
{
private List<Object> list;
public YourClassSwingWorker(List<Object> theOriginalList){
list = theOriginalList;
}
#Override
public List<Object> doInBackground() {
Thread t = new Thread(new ProcessorThread(list));
t.start();
}
#Override
public void done() {
// draw graph on GUI
}
}
class ProcessorThread implements Runnable {
//do lots of IO stuff
Thread t2 = new Thread(new SecondProcess());
t2.start();
}
This made sure all the work was being done by worker threads away from the GUI, and also ensuring that the SwingWorker itself wasn't doing all of the work, which might have been a problem.
For what I can read, it is used to dispatch a new thread in a swing app to perform some "background" work, but what's the benefit from using this rather than a "normal" thread?
Is not the same using a new Thread and when it finish invoke some GUI method using SwingUtilities.invokeLater?...
What am I missing here?
http://en.wikipedia.org/wiki/SwingWorker
http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html
Yes, you can accomplish what a SwingWorker does with vanilla threads + invokeLater. SwingWorker provides a predictable, integrated way to accomplish tasks on a background thread and report result on the EDT. SwingWorker additionally adds support for intermediate results. Again, you can do all of this yourself but sometimes it's easy to use the integrated and predictable solution especially when it comes to concurrency.
A code example:
import org.jdesktop.swingx.util.SwingWorker; // This one is from swingx
// another one is built in
// since JDK 1.6 AFAIK?
public class SwingWorkerTest {
public static void main( String[] args ) {
/**
* First method
*/
new Thread() {
public void run() {
/** Do work that would freeze GUI here */
final Object result = new Object();
java.awt.EventQueue.invokeLater( new Runnable() {
public void run() {
/** Update GUI here */
}
} );
}
}.start();
/**
* Second method
*/
new SwingWorker< Object , Object >() {
protected Object doInBackground() throws Exception {
/** Do work that would freeze GUI here */
return null;
}
protected void done() {
try {
Object result = get();
/** Update GUI here */
}
catch ( Exception ex ) {
ex.printStackTrace();
if ( ex instanceof java.lang.InterruptedException )
return;
}
}
}.execute();
}
}
The choice always depends on personal preference and use case.
The second method has an advantage when refactoring. You can more easily convert the anonymous class to an inner class when the method it's used in is too large.
My personal preference goes to the second, for we have built a framework where SwingWorkers can be added and are executed one after the other...
SwingWorker is an implementation of a common pattern (in .Net i read there is GuiWorker BackgroundWorker for this), where you have to do some work in a GUI program, but keep the GUI responsive. The problem is that often GUI libraries are not multi thread safe, so the common way to implement such workers is to use the message loop of the library to transfer messages into the event loop of the application.
These classes allow you to easily update your GUI. Usually, they have a update(int status) method that is called by the thread, dispatched by the class, and handled by the GUI, while the thread continues its work.
Using normal threads, you would need to code your own events or some other messaging mechanism for this task, which can be a pain if you need this functionality often. Using invokeLater in Java for example, you would intermix the code for updating the gui into the code for doing the work. The SwingWorker allows you to keep things separate.
to answer your question, you are not missing anything. this class is just a convenient utility for wrapping up the functionality you discribed (start another thread to do the background work and then invoking some final action on the EDT with the results).
When working with Swing, it is important to know that the main swing processing (ie. rendering) happens on a single thread (which is not your main thread). This is often called the Swing or awt event thread. Those familiar with the JDK pre 1.6 will remember the "grey rectangle" bug if you spent too much time in an event dispatcher for a swing component. What does this mean. In any swing application you will have 2 threads running that you will now have to deal with. Normally if all your operations within an event dispatcher (the code that gets fired say when a button is clicked) is short (ie. changing the state of a siwng button) you can just run this inside of the event dispatcher. If your application is going to call a web service or a database, or you application state is driven by external events (ie. jms) or you want to just make your UI more interactive (ie. build a list of items and be able to do something else) you should use a thread other than the awt event thread (the main swing one). So in these cases you spawn a new thread and do what you have to, and when the results finally come back, you then somehow have to create an event that can be executed by the awt/swing dispatcher. SwingWorker is a great little design pattern that allows you do to do this (the other way is SwingUtilities). It is particularly useful for doing fetch data from external sources or say long calculations (rendering a graphics scene). It helps automate the dispatch and subsequent re-integration of the results from an external thread (other than the awt thread). For async events (ie. an event from JMS needs to update a result, use SwingUtilities).
SwingWorker makes trivial example code much more concise. However it creates a ball of mud. Communications to and from the GUI and executed logic are all welded together. So, I'd not like to see it used in real production code.
SwingWorker is far easier than mucking with your own threads because it gives you two things that are painful to manually, thread coordination between the UI and the background process and doing loops effective, background work that keeps working and sending updates back to the UI incrementally, like process a large amount of data, or loading a large list. The disadvantage (or advantage) depends on how you look at it, is that it hides the underlying implementation, so future version may have different behavior, performance, etc, which may be undesirable. I've found it quite useful as the glue between a UI event and my own command code, the SwingWorker maintains the link to the UI and my code pumps data.