Before I go on discussing the basic query I would first like to state that I am fully aware of my question being against the standards of the AWT/Swing framework. My query is meant merely as a academic experience and should (hopefully) never be applied to real world applications.
The AWT/Swing framework is built upon a event based model which uses a single thread to dispatch events. All AWT/Swing related events events must be processed on the Event Dispatcher Thread (EDT) and any custom events that the programmer has programmed must be queued through the functions invokeAndWait() and invokeLater(). While this model ensures that the framework never suffers from any sort of thread concurrency issues it gives a big pain to programmers trying to write code around it (search swing issues on stackoverflow... quite a handful).
However... Years ago, before I got more familiar with the AWT/Swing model and the EDT I used to write code that violates many many java standards (code that'll make any reasonable programmer recoil in horror). One of these standards I violated was calling methods that updated the GUI through a thread thats not the EDT. To be precise it was a standard "long" task that resided on a secondary thread which periodically updated a JLabel with the current progress. Reviewing the code now I realized that despite the fact that the code directly violated the standard, it worked 100% of the time. I noticed no flickering, no corruption of text (since it was a JLabel), no random exceptions being thrown and no abnormal GUI behavior. Of course I know from one tiny example, one cannot simply determine the AWT/Swing standards are over-protective or unnecessary. And with this, my query lies:
For simple tasks like updating a JLabel (not even at a constant rate, maybe once or twice a second) is it truly necessary to perform it through the EDT? And what are the possible implications (apart from being despised by the whole java programming community) of this (I want a list of solid implications, not just "it might cause the EDT to mess up")?
Assume a model where only one thread updates the GUI (which is not the EDT) and the updates are infrequent and only update in atomic operations (updating strings, primitive data, etc) is it possible that the program can run free of problems caused by the EDT (I guess this counts as a hack?).
As a challenge, I was wondering if its possible anyone can come up with code that demonstrates a violation of the AWT/Swing model by dispatching events from another thread causing obvious and constant (as in I don't have to wait 2 hours for the GUI to flicker for 1 frame) problems?
And by the way, this might be unrelated but does a new EDT thread spawn for a new JFrame/Window object or do all of them run off the same thread? I can't imagine a resource-heavy multi-window system all running off one thread.
NB: I have never seen nor analyzed the source code of the AWT/Swing framework and all my knowledge is based on internet research and personal experience. If there is any mistake above, please feel free to correct me.
For those programmers still in shock from my example above, I have updated all my projects to comply to the standard (what a pain).
An example of where this fails: Set your JLabel to be right-aligned. Then drawing requires two steps - measuring the text, in order to calculate the position, and then drawing it. If you change the text while it is painting (say, due to an animation loop) the text will seem to jump occasionally.
In answer to your other question - there is only one EDT, for all GUI components.
Example of "constant and obvious" change: Suppose the JLabel has HTML content. In your background thread, after the text is set and a repaint is fired, a PropertyChange is also fired, which causes the UI delegate to reparse the HTML and set it in a client property (working in the background thread, although the UI assumes it is in the EDT because it is receiving an event).
So now you have a race condition: If the UI repaints the label (in the EDT) before it finishes calculating the HTML view in the background thread, it will paint the old HTML and your label will appear to not update.
You could say, "Well then, I just won't use HTML in my label." But the point is that situations like this are pervasive in the Swing libraries - a strong assumption is made everywhere that events are passed only on the EDT, and without reading a huge amount of the Swing source you can't guarantee that you won't run into a problem like this.
Related
I'm developing a SWING based Java application with multithreading.
The idea is to create a set of background "tasks/services" to do some tasks repeatedly.
My problem is how to implement multithreading (in the lower level of the application) that can interact with the GUI by displaying SWING components at some conditions.
I know I can use SwingWorker but using that I will turn my application more "gui oriented" wich I don't want to but in the other hand I also don't want to make my multithreading classes depended on GUI classes.
What are the options where?
Thank you in advance.
EDIT
I forgot to mention that this background tasks need to be started in the beginning and cannot be launched by the GUI (like a bootstrap process).
but in the other hand I also don't want to make my multithreading
classes depended on GUI classes.
What about using Observer/ Listener pattern? Your background tasks, launched by SwingWorker, can notify some other components when there is such need. #Xeon comment is pointing you in good direction.
Personal advice: start with some solution and then continuously refactor when code became not so readable.
btw. I hope you remember the old rule: Swing components should be accessed on the Event Dispatch Thread only ;)
You need to learn about concurrency design patterns, such as actors, futures, thread pools ect. Event driven means that you don't have blocking code, eg. rather than me waiting on you and constantly asking if you are finished with your task, you simply tell me once you are ready.
If you go the actor route you can wrap your gui class in a controller which is an actor which will process one message at a time. You need to be carefull with swing that you don't create event loops, as in event A triggers event B which triggers event A again and so on.
That's why an obserever pattern can be nice for displaying data.
But there is no silver bullet for concurrency unfortunately, the actor model is picking up, as well as futures, (take a look at akka), but it is essentially a difficult task so it will always be hard to get right.
Essentially I would say that the easiest approach is to make very strict rules on the sort of concurrency you are willing to accomodate, you need to think about the consequences of adding each bit of parallel functionality, and what effect it has. Then design your code based on that using a well established concurrency model.
What you want to do is the standard way most designers would want to do it, that is, have a background worker class which is independent of the GUI.
Creating a class, MySwingWorker, which extends SwingWorker and which calls your background classes is the standard approach. You may want to create one or more dialog classes to wrap your usage of MySwingWorkers, depending on the complexity of your application.
I start several(threads) instances of a java class that receives an "input" and based on that generates an "output" on out it out on the standard output(screen). I would like to add an option that would enable me to send this output to a single JFrame (text area). What is the best way of doing this? Up to this point my program was totally GUIless but I would like to make it a bit more GUI friendly and add this option.
The challenge is that at any given point I could have several threads running. Any design or code snippets would be greatly appreciated.
As MadProgrammer points out, a nice, encapsulated way of doing this is SwingWorker.
That said, here is the general theory:
All updates to Swing components must be done on the Swing event dispatch thread (there are some exceptions, but not relevant here). This is achieved by SwingUtilities.invokeLater() (and occasionally invokeAndWait() ).
The Swing runtime will then queue up the changes you want to make and call them one at a time. This makes the entire problem of updating your text area pretty trivial: just create a Runnable with the text you want to append, pass that to invokeLater(), and have your Runnable grab the document model of the text area and append your desired text to it.
SwingWorker can encapsulate some of the complexities of background thread management, but I encourage you to do it the 'hard way' a time or two (and your use-case is actually easier to do the 'hard way'). That way you can appreciate what SwingWorker does for you when you do need it.
You need not to convert your existing threads to SwingWorkers. Just let them from time to time send messages to JFrame in a way like this:
EventQueue.invokeLater(new Runnable(){
// update GUI
});
To avoid boilerplate code, it is good to wrap programming interface to the screen with a java.lang.reflect.Proxy. An example of such wrapping is at SwingProxyActorTest.java.
I have a GUI and the GUI is starting another thread (Java). This thread is starting a class which is crawling many websites. Now I want to show in the GUI how many websites are crawled and how many are left.
I wonder what's the best solution for that.
First idea was to start a timer in the GUI and periodically ask the crawler how many is left. But I guess this is quite dirty...
Then one could pass the GUI to the crawler and it is calling a GUI method every time the count of ready websites changes. But I don't think that's much better?
What is the best way to do something like that?
It depends.
Ask the crawler how much work it is done isn't a bad idea. The benefit is you can actually control when an update occurs and can balance out the load.
The downside is that the information may go stale very quickly and you may never get accurate results, as by the time you've read the values, the crawler may have already changed them.
You could have the crawler provide a call back interface, which the GUI registers to and when the crawler updates it's states, calls back to the GUI.
The problem here is the UI may become swamped with results, causing to lag as it tries to keep up. Equally, while the crawler is firing these notifications, it isn't doing it's work...
(Assuming Swing)
In either case, you need to make sure that any ideas you make to the UI are made from within the Event Dispatching Thread. This means if you use the callback method, the updates coming back will come from the crawlers thread context. You will need to resync these with the EDT.
In this case you could simply use a SwingWorker which provides mechanisms for syncing updates back to the EDT for you.
Check out Concurrency in Swing for more details
register a callback function to your thread. when your data is dirty, invoke this callback function to notify GUI thread to update. don't forget to use synchronization.
The following line:
SwingUtilities.updateComponentTreeUI(aComponent);
is making my GUI unresponsive.
When invoking this method to update the laf on a large portion of a GUI, it takes a lot of time, and so makes the GUI unresponsive during this operation.
Since this operation is manipulating the GUI, one can't use a SwingWorker for this either.
From the SwingWorker documentation:
Time-consuming tasks should not be run on the Event Dispatch Thread.
Otherwise the application becomes
unresponsive.
Swing components should be accessed on the Event Dispatch Thread
only.
The problem here though, is that the operation is accessing Swing components and is time-consuming.
Is there a good way to prevent this unresponsiveness?
Since what you do is changing the L&F, and that might severely impact the appearance and usability of the GUI, ask yourself whether you really want the application to be responsive during that time. It may be better to display a message ("Please wait..." or something) using the glass pane, and freeze the GUI while the L&F is updated.
Now, as others have suggested, you may want to investigate why updating the component tree is so slow.
I was going to suggest looking through your GUI to identify any custom or third-party components that contained a lot of sub-components or that had any unusual or inefficient method to revalidate itself. It looks like that was the case, as you mentioned the date picker was a serious bottleneck.
You suggested splitting the calls to updateComponentTree into several sub-tasks that allow events to occur in between, which might be a 'hack' but isn't too bad, unless the change of font changes the sizes of elements and may cause the user to miss a button etc.
If possible, I would suggest looking at the code in the date picker component and see if you can rewrite it so that instead of hiding the components in the pop-up, it actually removes/disposes them, and recreates them when necessary. This should have no noticeable effect on the responsiveness of the date picker when it's being used, but will certainly speed up component tree updates when the pop-up is not visible.
In Swing, the GUI is supposed to be updated by the EDT only, since the GUI components are not thread safe.
My question is, if I have a single thread, other than the EDT, that is dedicated to update a specific component, and this component is not accessed by any other thread in my program, only this dedicated thread, is it ok? In my case I have a JTable and a thread receives information from the network and updates the table (without using EventQueue.invokeLater). All the other components are updated from the EDT. I have not seen a problem so far, and I was wondering if a bug will surface eventually.
UPDATE
My purpose was to update the table in real-time. The data come constantly from the network and for this I dedicated 1 thread just for the table, to update it constanlty as they come. If I use the SwingUtilities.invokeLater, this means that the table will be updated when the EDT is available. Is not swing supposed to be used for real-time update requirements?
Instead of trying to reason about whether it will or won't work, I would just stick to the well-known 'rule' which is that you should only interact with GUI components using the event dispatching thread. When you receive data from the network, just update the table using SwingUtilities.invokeLater (or invokeAndWait).
You might not see problems straight away, but it's quite possible you might do in the future.
There are a few methods documented as thread-safe. I believe a few less in JDK7, because it turns out some of them are unimplementable as thread-safe. For the most part Swing is thread-hostile - it has to be used from the AWT EDT thread. This is largely because it uses EventQueue.invokeLater internally at "random". Also there is hidden shared state (you can change the PL&F without having to tell each component for instance). Some classes you may be able to treat as thread-agnostic, but they are not documented as such.
So the answer is, always use the EDT for Swing. As with most threading bugs, you might seem to get away with it and then suddenly fail in production. The bug is likely to be difficult to diagnose and reproduce (particularly if it only happens in production on certain systems). Fixing a code base that is severely broken may not be fun. Keep it clean from the start.
You must update GUI components on the EDT. Period. (There are a couple of legacy exceptions to this rule - but they were all silently putting things over to the EDT anyway). The EDT operates as a message pump (as most windowing systems do) - you have to live within that constraint if you want to update GUI components.
If you want your table to update quickly, keep the EDT clean - don't put any huge load onto it.
If you are working with updating live tables, I strongly recommend that you take a look at GlazedLists - they have a very, very good SwingThreadProxyList implementation that takes care of efficiently posting updates to the EDT. You have to agree to drink the GlazedLists koolaid to go this route, but it is mighty tasty koolaid (I love GL).
Is not Swing supposed to be used for real-time update requirements?
No. You may be able to update your data model at a sufficient rate, but the GUI is typically subordinate. You may be able to take advantage of any network latency in your environment. Alternatively, you may need to consider something like Oracle's Sun Java Real-Time System.
You can improve the "liveness" of the EDT by keeping updates brief and using the minimal, correct synchronization. Several alternatives are discussed here.
It is an absolute rule, unless you want race conditions. The event dispatch thread is fast enough for our CCTV app's display not to need hacks.