Signalling between threads in Java

Various releases of Java have introduced more sophisticated concurrency patterns to Java. You don’t need to build your own thread pooling techniques, or queues between threads. However, for a lot of uses, the synchronized keyword is pretty much all you need.

I had a recent use case, for which it seemed that there wasn’t a sophisticated library class, nor was a single line of code enough. I wanted an object on one thread to be able to signal when it was done and for other threads to be able to block until that signal was made.

This is not that difficult to do, but you can’t just do this:

private Object event = new Object();

// for consumers to use to wait for the event
public void waitForEvent() {
    // to do a wait, we need to acquire the monitor
    synchronized(object) {
        // wait until object notifies - which relinquishes the lock on the object too
        object.wait();
    }
}

The above, which illustrates the synchronization pattern for notify and wait in Java, isn’t quite enough. The reason it’s not enough is that in concurrent processing, it’s possible for the event to be signalled before the waiting thread calls waitForEvent. If the event has already been signalled, and you start waiting for a notify that never comes, then you’re blocked either forever or until a timeout.

Reading up on the subject, it seems it’s common to put some sort of boolean alongside this pattern.

Furthermore, it turns out that wait can abort spuriously without being notified, so if you’re not checking a boolean in a while loop, you may wake up early and be in an error state. This code needs taming!

My next advice. Object orientation ALWAYS helps with thread safety stuff in Java. I created a Signal class, whose job is to store the signal and allow callers to wait for it.

I’ve shared this code here on GitHub. Feel free to copy it and use it as you wish.

Here’s a snippet:

/**
 * Set the done flag
 */
public void setSignal() {
    synchronized (signalSync) {
        signalled = true;
    }
    synchronized (this) {
        notifyAll();
    }
}

What’s quite nice about this is that the object orientedness of it avoids your consumer having to know anything about concurrency to use it. Using this signal is very easy – it just acts like a flag, but you can wait for it as well as read it.

The following unit test (also in GitHub) shows how the signal makes it easy for threads to set gates on each other. Note that the final signal in this example could have been done with thread.join(), but wasn’t for the purposes of the test. Also, note how Junit’s @Test(timeout= ) syntax is used to ensure that the test which is running waiting threads, doesn’t go on forever owing to a bug.

@Test(timeout=TIMEOUT)
public void interThreadSignalling() throws InterruptedException {
	final Signal threadStarted = new Signal();
	final Signal threadAllowedToProceed = new Signal();
	final Signal threadFinished = new Signal();

	Thread thread = new Thread(new Runnable(){

		@Override
		public void run() {
			// set that we've started
			threadStarted.setSignal();

			// wait until we're allowed to proceed
			try {
				threadAllowedToProceed.waitForSignal();
			} catch (InterruptedException e) {
				// do nothing here
			}

			// signal we've finished
			threadFinished.setSignal();

		}

	});

	thread.start();

	// wait for the thread to have started
	threadStarted.waitForSignal();

	// thread should not have finished - so wait to see if it has and check it hasn't
	threadFinished.waitForSignal(SHORT_TIME);
	assertFalse(threadFinished.isSignalled());

	// then signal the thread to finish
	threadAllowedToProceed.setSignal();

	// then wait indefinitely for the thread to say it's finished
	threadFinished.waitForSignal();

	// reaching here before the overall timeout is proof that the 
	// signalling works between threads
}

CountDownLatch

As my colleague Zoltan mentions in the comments below, if you want some threads to wait for an event, then creating a CountDownLatch of size 1 and then calling countDown will trigger all waiting threads.

However, one disadvantage of CountDownLatch is that once the countdown is reached, you cannot start over. The Signal solution has been useful for me when some state could flip over and over during runtime. For example, there are messages available – for which you can keep it true until there are none left, then set it to false, have all the threads wait for it to go true, and then flip it to true when more messages come in, waking up the waiting threads.

August 2019

The above post was written a while back and has been quite popular on the site. I’ve just updated it with some additional battle-hardened improvements so that readers can use my best version of Signal.

The original article used synchronized on functions, essentially relying on synchronized(this) – that’s less effective, as the signal state and the notification to waiting threads are two separate concerns of the Signal class.

Related Reading

2 comments

  1. This is a nice solution, but if you just need to wait for another thread to finish, then using CountDownLatch might be simpler.

    • CountDownLatch has its place, though what could be simpler than just waiting for an event 🙂

      In the use case I faced, I had multiple threads to block until a single event had occurred.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s