November 17, 2006

Good Threaded Code 2

I've been writing concurrent code in Java for some years now and like to believe that I've learnt a few things in the process.

In Java all objects have a mutex and monitor associated with them and so any object can be used to provide concurrency control and signalling. Java allows code to synchronize on any objects to which it has access, this includes the object declaring the code. In fact Java positively encourages you to synchronize on the declaring object by providing synchronized methods and allowing synchronized(this).
For example:
public class ConcurrentClass
{
public void doSomething()
{
//do something thread safe...
...
//do something not thread safe...
synchronized(this)
{
...
}
}

public synchronized void doSomethingElse()
{
//do something not thread safe...
...
}
}
When you call doSomething() or doSomethingElse() the mutex of the ConcurrentClass instance is only held for the duration of the synchronized block or the synchronized method.

I believe that this approach violates encapsulation. The mutex used to control the internal concurrency issues of the ConcurrentClass instance is available to other classes and so other classes can participate in the internal concurrency concerns of the ConcurrentClass instance. At first sight this might not seem a bad thing but just stop and think for a second. This means that concurrency control for a specific resource can be spread across several classes. Rather than debugging one class you may have to debug many.

I would far rather write something like:
public class ConcurrentClass 
{
private Object mutex = new Object();
...

public void doSomething()
{
//do something thread safe...
...
//do something not thread safe...
synchronized(mutex)
{
...
}
}

public void doSomethingElse()
{
//do something not thread safe...
synchronized(mutex)
{
...
}
}

}
This means that the mutex and thus the concurrency control is fully encapsulated within the class.

An example where the lack of encapsulation can cause a problem is in java.lang.Thread. I have seen application code that sub-classes java.lang.Thread and uses synchronized methods or synchronize on the thread object. If the application code deadlocks it becomes impossible to use any of the normal methods to control the thread as they are all synchronized on the thread themselves.

No comments: