by Uwe B. Meding

Mutex objects and/or semaphores are use to manage resource access contention. In Java, the standard is to use the synchronized guards around critical pieces of code, to make sure that only specific threads can access a resource. One of the issues with these guards is that they are very local and promote a programming structure that force the implementation of choke points. These points represent a well-defined point at which all transactions with a resource are funneled. In large multi-hosted systems, points like this become a scaling and performance problem.

In this blog I am showing how to design re-entrant mutex objects in Java, which allow resource management over a much larger system infrastructure. For example, stateless application servers, can now hold a lock across a set of independent calls. A downloadable version is at the end of this article.

The basic functionality is to use the current active thread to manage the lock and create a “revolving” platform for the owners of a lock. The following snippet waits (possibly indefinitely) for a lock to become available:

synchronized (this) {
    if (owner == Thread.currentThread()) {
        // thread already owns this mutex
        return true;
    }
    try {
        while (owner != null) {
            this.wait();
        }
        // acquired mutex
        owner = Thread.currentThread();
    } catch (InterruptedException ex) {
        // we were interrupeted while acquiring mutex
        notify();
        throw ex;
    }
    return true;
}

This snippet waits for some time to acquire a lock. For this we use the expiring wait method. This will guarantee that we are not waiting indefinitely for a resource to become available:

synchronized (this) {

    if (owner == null) {

        // acquiring mutex
        owner = Thread.currentThread();
        return true;

    } else if (owner == Thread.currentThread()) {

        // we already own the mutex
        return true;

    } else if (msecs <= 0) {         // we did not get the mutex, the other thread did
        // not release it
        return false;

    } else {

        // waiting for the mutex to become available
        long waitTime = msecs;
        long start = System.currentTimeMillis();
        try {
            while (true) {
                this.wait(waitTime);
                if (owner == null) {

                    owner = Thread.currentThread();
                    // we acquired it after waiting
                    return true;

                } else {

                    waitTime = msecs - (System.currentTimeMillis() - start);
                    if (waitTime <= 0) {
                        // failed to get mutex in time
                        return false;
                    }
                }
            }
        } catch (InterruptedException ex) {
            // we got interrupted while acquiring the mutex
            notify();
            throw ex;
        }
    }
}

Releasing is fairly straight forward, the key is to ensure the thread releasing it is indeed the owner before we notify all other threads that are currently waiting for the lock.

Thread thread = Thread.currentThread();
if (owner == null) {
    // trying to release unowned mutex
    return;
}
if (thread == owner) {
    // releasing mutex
    owner = null;
    this.notify();
}

Here are links to downloadable versions of this code.

Leave a Reply