Swing multi-threading issues

Most of the problems in bad Swing applications can be traced to improper thread usage. Swing uses a “single-threaded” painting model, in a way that all components are painted from a single thread.

In theory, modifying visual components from a thread other than the event processing thread can lead to a Deadlock or cause other synchronization problems. In real life, nothing fatal is going to happen if you do not use the event dispatch thread to update visual components. However, you may experience strange unsynchronized behavior or make the application a lot less responsive.

Most multi-threading problems arise in event handlers that can block or require a lot of processing. Simple event handlers usually just update the visual components and return, and they do not require special multi-threading considerations.

If the event handler can block or requires a lot of processing, and you process everything from the Event Dispatch Thread, your users will see “sticky” components. A reasonable solution usually is starting a new Thread of execution and delegating the event processing to that thread. However, if you neglect the Event Dispatch Thread, several problems can arise such as: batch updates and unsynchronized repainting.

"Sticky" components

“Sticky” components are displayed on the screen in an intermediate position - for example, a button remains pressed while the contents of a TextArea are saved to disk. This is not user-friendly, and most users will think that the application blocked because of an error. A proper user-friendly behavior would be to allow the button to return to a normal state, and then show the Wait cursor while the file is being saved.

To solve this problem, start a new thread of execution in the event handler. Change the cursor to Wait before starting a new Thread, and then change it back to Normal after the event is processed. Remember to use SwingUtilities.invokeLater() to process the cursor update (and all other visual updates) from the new thread. See Block Components During Threaded Event Handling) for an example.

Batch updates

Batch updates are more than one update requests manifested as a single screen update, usually on the end of the event handling procedure. This problem is manifested as partially displayed components on the screen, traces of old components, or having several delayed updates show up on the screen at once when you actually expected a sequence of visible updates.

This is normally not a big problem, except when you really want to notify the user about something during the event handling procedure. The source of batch update problem is asynchronous request processing - when you change a component, you are actually posting a repaint request, not directly changing its representation on the screen. So, if you keep the event dispatch thread busy, it is likely that all your requests will be processed when the procedure ends.

This is especially noticeable in graphics-intensive applications such as video games, that have a lot of rapidly-changing images on the screen. On a test system (Celeron 2, 256 MB RAM), this problem started showing up when the screen contained about 80 JLabels containing images that were rapidly updated.

A specially interesting form of batch update problem is when two changes are inverse - for example, changing the cursor to Wait and then back to Normal. When these two updates are performed in a batch, the user does not notice anything.

Batch updates can be fixed by properly wrapping the visual change requests in SwingUtilities.invokeLater() calls.

Unsynchronized repainting

Unsynchronized repainting is manifested by visible changes on the screen in an improper order. For example, frames of animations are not shown in the right sequence. Unsynchronized repainting is caused by same errors as batch updates, and can be fixed in a similar way. To guarantee the order of visual updates, start a new Thread in the event handler, and then use SwingUtilities.invokeAndWait() in that thread to display a visual change on the screen, and wait for it to be processed. For example, SwingUtilities.invokeAndWait() can be used to show each frame in an animation.

Best practices

Solutions to common problems

External links

 

Comments? Corrections? Contact us or Login to edit pages directly (registration is free and takes less than displaying a JLabel)
  other/swing_threading.txt · Last modified: 2006/06/02 10:47 by 159.53.78.144 (caa)
 
Recent changes | RSS changes | Table of contents | News Archive | Terms And Conditions | Register