RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Use Callbacks to Isolate Concurrency Bugs

By restricting all object data access to a callback mechanism, a Java server can contain all concurrency issues in a single place, making it much easier for you to see if concurrency constraints have been violated.

ne of the most common errors Java programmers make when they first learn multi-threaded programming is to misunderstand locks. They believe that locking an object prevents access to its fields and methods, when in fact a lock on an object serves only to prevent other threads from gaining the same lock. This confusion, while understandable, can lead to vexing concurrency bugs.

In fact, many concurrency bugs come down to particular data being accessed at the wrong time—usually while someone else is changing it. Concurrency models in general rely on a set of interconnected synchronization zones, spread out over a number of source files. Such designs are vulnerable to "concurrency rot", in which the delicate relationships between different elements become hard to manage as code changes. Wouldn't it be nice if you really could lock an object and keep it all to yourself while you used it?

This article describes a method for constructing high-load concurrent servers, which prevents concurrency rot. By restricting all data access to a callback mechanism, the server can contain all concurrency issues in a single place, making it much easier to see if concurrency constraints have been violated.

Callbacks for Single-Threaded Access

Follow this tutorial to design and build a server that uses callbacks for single-threaded access. Objects containing sensitive data will be accessed linearly—that is, they will be available to only one thread at a time.

The way you will enforce this is opposite from the way it is usually done. Normally, multiple threads attempt to gain access to a resource by competing for a lock. The thread that gets the lock has access until it releases the lock, at which point the next thread gets access.

In this design, however, you use a callback. You pass a callback object with a method called access() to a gatekeeper. The gatekeeper passes the sensitive data to this method of the callback object. When the callback object is done using the data, the gatekeeper passes the data to the next callback object.

In a sense, this design isn't really different from the typical one: each object or thread gets a turn, and during its turn it has exclusive access. But instead of having the threads contend for control, the control is entirely in the hands of the gatekeeper object, which decides who gets access when.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date