Asynchronous Event Handling: Get Rid of Nasty Applet Pauses

Wednesday Nov 22nd 2000 by Greg Travis

This article describes a common pitfall in event-driven programming that can harm the responsiveness of the user interface, and describes a technique for fixing the problem.

A responsive user interface is one of the most important considerations in making an application intuitive and friendly. This article describes a common pitfall in event-driven programming that can harm the responsiveness of the user interface, and describes a technique for fixing the problem.

The Problem

Here's a common error a beginning applet programmer makes. He creates a graphical applet that responds to user input; initially everything is fine.

But the programmer continues to evolve the applet; he modifies the graphics routines, making them do more sophisticated and complicated things. Pretty soon, the applet seems to be 'hanging' for extended periods — that is, it's so busy doing computations or graphics rendering that it doesn't seem to be responding to user input.

Since the programmer doesn't know about the one-event-thread rule, he doesn't know why. And since events are only being delayed, not lost, he might just ignore the problem.

The Cause of the Problem

Here's the one-event-thread rule: most Java implementations have only a single thread for doing all event processing. If an applet performs a lengthy calculation in response to an incoming event, the user interface may be tied up for the duration, giving the impression that the applet has 'hung'.


One solution to this problem is to create separate threads for doing large computations. These threads are dedicated to doing things that take too long to be done in the main event thread.

Using a separate thread to perform something that might have been done in the main thread is sometimes called asynchronous processing, as opposed to synchronous processing.

In our example, we are going to set up a system that is conceptually simple (and later on, we'll talk about ideas for making it all a bit more sophisticated). Our system is going to spawn a thread to deal with each event. The advantage of this is that we'll guarantee that the event thread will never be tied up in a long computation.

We're going to create a class called

. Each time an event comes in, instead of allowing the system to process it normally, we create an
to handle it, and immediately return. All the main event thread has to do is create the thread, and it's work is done; the time spent doing this is negligible, and so we keep our interface responsive. Meanwhile, the
that we've created is going to go off 'in the background' and process the event. No matter how long this processing takes, it won't interfere with the main event thread.

Here's how you use


  new STEventThread( this, event );

This single line of code creates a new

, which automatically starts itself running in the background. That's all you need to do!

But where do you call this? There are a number of plausible answers to this question, but in our example, we are going to override the

method in our applet, like so:

  protected void processEvent( AWTEvent event ) {

    // Check to see if we are using asynchronous processing
    if (asynch) {

      // If we are, all we have to do is spawn the thread
      // (Asynchronous processing)
      new STEventThread( this, event );
    } else {
      // If not, we carry out the default behavior by calling
      // the processEvent() method in our superclass
      // (Synchronous processing)
      super.processEvent( event );

Note what we've done here. First of all, we make a decision about whether we really want to use asynchronous processing, based on the value taken from an applet parameter. This lets us easily compare the same applet, with and without asynchronous processing, by changing only the value of the parameter.

Assuming we are using asynchronous processing, we create a new


Meanwhile, over in

, let's see what's happening.

  public STEventThread( STEventProcessor step, AWTEvent event ) {
    // Store stuff in member variables
    this.step = step;
    this.event = event;

    // Start up a thread
    new Thread( this ).start();

The constructor is also simple — we stuff our parameters into member variables so we can get at them later, and we start up a thread.

When the thread starts, here's what happens:

  public void run() {
    // Process the event
    step.stProcessEvent( event );

Now, we're running inside our new, 'background' thread. And again, it's just a tiny bit of code. What we're doing here is calling back into our applet and resuming the processing of the event. Without further ado, let's go back to our applet and see what


  public void stProcessEvent( AWTEvent event ) {
    // Resume normal processing of the event, but from within
    // our 'background' thread
    super.processEvent( event );

The reason we need this stub routine is because

is a protected method, and so we can't call it directly from
. We've defined an interface,
, which our applet implements by defining the method
, and it is through this interface that we call this method.

If you forget for a moment about the thread we've spawned, this seems like the long way around: instead of allowing the event to be processed by

, we instead grab the event, pass it over to
, which passes it back to our applet, which then calls
. This round trip isn't a waste, however, because when we finally do the actual processing, we are running inside our 'background' thread. In fact, that was the point of the whole trip between the classes — we wanted to call
on the event, but in a separate thread.

Let's compare the journeys of two identical events, one being processed normally, and one being processed by our special setup.

(Note: steps carried out in the main event thread are in blue; steps carried out in a 'background' thread are in green.)

Synchronous path

  1. User clicks the mouse button inside the applet
  2. System generates event
  3. System passes event to
  4. Event is passed to MouseListener
  5. MouseListener processes event
  6. Applet.processEvent()
    is done

Asynchronous path

  1. User clicks the mouse button inside the applet
  2. System generates event
  3. System passes event to our replacement for
  4. Our
    creates a new
  5. Applet.processEvent()
    is done
  6. A new thread is started
  7. In the new thread,
    passes the event to
  8. stProcessEvent()
  9. Event is passed to MouseListener
  10. MouseListener processes event
  11. Applet.processEvent()
    is done

Try it out

This page

contains two instances of our example applet. The left instance is set to use synchronous processing, while the right one is set to use asynchronous processing.

If you click on the right applet, you'll see a white square move across the screen, filling in the space behind it with a new color. If you click a few more times, you see several white squares filling in the applet, each with a new color.

This 'slow fill' is our special, slow computation. It takes several seconds to complete, and, thus, if it were implemented naively, would tie up the user interface for those several seconds. However, the applet running on the right side doesn't have this problem. Each filling process is run in a different 'background' thread, and so the applet can continue to process new events while the fill is happening. In fact, this is why you can click several times and see several fills happening at once — if we were using only one thread, the first fill would have to complete before the second one could start. This is what you'll see if you click on the applet on the left.

Actually, precisely what happens in the left applet depends on what implementation of Java you are using.

In some implementations, you'll see nothing happen, and then suddenly, the entire window will change to a new color. This is because the left applet is using the main event thread to do the fill, and it just so happens that this thread is also used to respond to

requests. Because this thread is tied up, it cannot draw the window, and thus we cannot watch the progress of the fill.

In fact, in some implementations (one example is JDK 1.1.7B for Linux, from Sun), the situation is even worse. The main event thread is shared between the applets, which means that if you are watching the right one do some filling, and you click inside the left one, both applets will appear to be frozen, because the single main event thread is busy doing a fill on the right, which prevents either applet from drawing anything.

In other implementations (for example, Netscape 4.72 for Linux), it seems that each applet has its own event thread. If you click in both applets, the left one will be tied up, and thus will show nothing happening, but the right one continues merrily along doing its fills. Your mileage may vary.

Further considerations

  • If you use asynchronous processing of events, you have to make sure to make the appropriate code thread-safe. This is particularly true if you are converting an existing applet to be asynchronous. It is quite possible that there are data structures and methods that were meant to be used only from a single thread; if you are calling them from 'background' threads, you may have to throw some synchronization blocks around some of your code to keep it from breaking.

  • This implementation creates a 'background' thread for every single event passed to this Component. As mentioned at the beginning of the article, this is conceptually simple. While asynchronous processing is a good thing for our slow fills, it is a waste of speed and memory for those events which can be handled quickly. Additionally, since multithreaded code is more complex than single-threaded code, we might be making some of our code unnecessarily complex. A solution for this might be to make only certain events asynchronous, allowing others to be processed normally. This choice could be made within our version of


About the Author

Greg Travis is a freelance programmer living in New York City. His interest in computers can probably be traced back to that episode of "The Bionic Woman" where Jamie runs around trying to escape a building whose lights and doors are controlled by an evil artificial intelligence that mocks her through loudspeakers. He's a devout believer in the religious idea that, when a computer program works, it's a complete coincidence. He can be reached at

Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved