Chapter 4. Wait and Notify

In the previous chapter, we took our first look into issues of synchronization. With the synchronization tools introduced, we now are able to have our own threads interoperate and safely share data with each other. It is possible for threads to share data without any race conditions. However, as we shall see, synchronization is more than avoiding race conditions: it includes a thread-based notification system that we’ll examine in this chapter.

Back to Work (at the Bank)

Having just completed a sweep of all the code in the ATM system—synchronizing any potential problems using the techniques of Chapter 3—we have made the system much more robust. Many little hiccups that used to occur no longer show up. But most important, our BusyFlag class allows us to quickly make the modifications required by our president. The use of the BusyFlag class in this situation allows it to be adopted as a corporate standard and used throughout the whole ATM system.

As far as our manager is concerned, we’re heroes—until another problem occurs: it turns out that a portion of the ATM system is facing performance problems. This portion of the system was developed by a coworker who made extensive use of the BusyFlag class. Since it is our class, we are given the task of trying to correct the problem. We start by revisiting the entire BusyFlag class:

public class BusyFlag {
    protected Thread busyflag = null;
    protected int busycount = 0;

    public void getBusyFlag() {
        while (tryGetBusyFlag() == false) {
            try {
                Thread.sleep(100);
            } catch (Exception e) {}
        }
    }

    public synchronized boolean tryGetBusyFlag() {
        if (busyflag == null) {
            busyflag = Thread.currentThread();
            busycount = 1;
            return true;
        }
        if (busyflag == Thread.currentThread()) {
            busycount++;
            return true;
        }
        return false;
    }

    public synchronized void freeBusyFlag () {
        if (getBusyFlagOwner() == Thread.currentThread()) {
            busycount--;
            if (busycount == 0)
                busyflag = null;
        }
    }

    public synchronized Thread getBusyFlagOwner() {
        return busyflag;
    }
}

Upon revisiting the BusyFlag class, we notice the call to the sleep() method. We originally used this method to avoid eating up too many CPU cycles. At the time, we considered this an open issue. If the getBusyFlag() method sleeps for a long period of time, this might cause the method to wait too long and hence cause a performance problem. Conversely, if the method does not sleep enough, it might eat up too many CPU cycles and hence cause a performance problem. In either case, this has to be fixed: we have to find a way to wait only until the lock is freed. We need the getBusyFlag() method to grab the busyflag the moment the flag is freed and yet not eat any CPU cycles in a polling loop. We’ll solve this problem in the next section.

Get Java Threads, Second Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.