Ups and downs of CountDownLatches – an example

CountDownLatches are an elegant means of synchronizing threads. However, I’ve rarely seen them in actual use in production software. Well, this may be related to two simple reasons:

  1. They are less known
  2. They might require extra care than usual lock objects

First things first. What’s a CountDownLatch? Well, it is a not very tricky construct for -as mentioned earlier- coordinating threads. You will observe when creating such an object, that a CountDownLatch takes one single construnctor argument: the count (of type int. More on this in a second). The construct itself has three important methods:

  • countDown(); Each call to this method will decrease the value of the count, exactly by one
  • await(); blocks the thread as long as the count is greater than zero. As soon as the count is down to zero, the blocked thread will be given a chance to run again.
  • await(timeOut, timeUnit); well, it’s pretty self-explanatory. It does the exact same thing as the one above, only with a configurable timeout.

It is easy to see that CountDownLatches are best when we know ahead how many threads we are coordinating. A quick example on this situation (sorry for the following physics stuff, I couldn’t come up with any better or fancier): It is known that the magnetic field around a wire is given by the formula: wire.
Let’s suppose we are given the radius (r), but have to calculate the exact value for magnetic permeability(u0) and current(I). Let’s also suppose those are calculated by separate threads, and we can calculate the value for the magnetic field(B) as soon as we have those values. In this case, it is obvious that exactly two pieces of data have to become available before we can start calculating, so it should be easy to use CountDownLatches. We can come up with a solution like the one below, in no time:

	private final CountDownLatch calculationLatch = new CountDownLatch(2);

	public MagneticFieldCalculatorWithLatch(double radius) {
		this.radius = radius;
	}

	public void setPermeability(double permeability) {
		this.permeability = permeability;
		calculationLatch.countDown();
	}

	public void setCurrent(double current) {
		this.current = current;
		calculationLatch.countDown();
	}

	public void calculateMagneticField() throws InterruptedException {
		calculationLatch.await();

		double field = (permeability * current) / 2 * Math.PI * radius;
		System.out.println("The magnetic field around the wire is: " + field);
	}

It’s pretty nice, huh?  I particularly like that I don’t have to include the keyword synchronized in all the signatures (just try making those methods synchronized, you will instantaneously cause a deadlock), there isn’t a boilerplate loop to check whether the data is available etc. Simply cool.

With a classical solution, we would have something like:

	public MagneticFieldCalculatorWithNotifications(double radius) {
		this.radius = radius;
	}

	public synchronized void setPermeability(double permeability) {
		this.permeability = permeability;
		notifyAll();
	}

	public synchronized void setCurrent(double current) {
		this.current = current;
		notifyAll();
	}

	public synchronized void calculateMagneticField() throws InterruptedException {

		while (!dataAvailable()) {
			wait();
		}
		double field = (permeability * current) / 2 * Math.PI * radius;
		System.out.println("The magnetic field around the wire is: " + field);
	}

	private synchronized boolean dataAvailable() {
		return permeability != null && current != null;
	}

Which seems (probably because I’m biased, as this is a post on latches) more tedious.

However, this second solution has a clear advantage compared to the first one (and this is why i put earlier that latches “require extra care”), namely that is more robust. Should you call setCurrent(…) in the first example twice, the calculation is corruptedThat is because upon the first call, the value of the current is set, and the count is decremented to one – just as expected. When you call the method for the second time, though, the value of the current gets overwritten and the latch’s count gets decremented again, reaching the value of zero. At that point the thread waiting because of the await() method call is woken up, however, the calculator has the value for the current only, and not for u0 (which is initialized to 0 by the JVM). Easy to spot that the calculation will be resulting in the magnetic field being equal to 0.

The second solution, however, will not exhibit this weakness, as the while loop guards against such usage errors.  That while loop will always put the thread back to the waiting state, unless we have all the required data available. The worst that can happen in the second case (provided that you call setCurrent twice and setPermeabiliy zero times) is an infinite loop, which is easier to notice, after all (in a large system, at least).

In conclusion, use CountDownLatches for elegant solutions, but use them with care. And of course, don’t rely on them excessively, use them in apropiate situations only.

Advertisements

Author: tamasgyorfi

Senior software engineer, certified enterprise architect and certified Scrum master. Feel free to connect on Twitter: @tamasgyorfi

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s