Every Object Isa Monitor

[Voting on JavaDesignFlaws page.]

In Java every object can be synchronized against. In other languages you have to use special structs/objects prepared especially for locking.

Other useful capabilities/aspects require specific interfaces in Java. If you want to raise something as an exception, it must implement Throwable. If you want to stream it out to disk, it had better implement Serializable. Why oh why oh why couldn't locking require an object implement a Lockable interface?

I do not see it as a design flaw. It gives very good place to perform actual locking - for example you do not have to worry which lock use for array access - use array reference itself. Second benefit is an ability to have synchronized methods - they implicitly lock 'this' object and are nice shortcut.

Then have arrays implement Lockable. And if you want synchronized methods but don't want to have the object implement Lockable, Java could still require that Class implements lockable, so that you could lock on the class.

I suppose that original creator of this entry was worried about performance. It is not bad - in most recent jvms monitors are free, as long as you don't use them (I know it sounds stupid, but idea is that you do not pay the cost unless you need it - and in this case you would have to alloc separate monitor anyway).

-- Artur

Actually I suggested this as a flaw because making any object a monitor obfuscates the multi-threaded behaviour of Java code. Choosing where and how threads synchronise is an important part of system design. If synchronisation could only happen within monitor objects, and monitors had to extend a Monitor base class, programmers would be forced to highlight how threads synchronise within their code. However, Java allows any method to put a synchronized block around any object, even ValueObjects!


Artur, in what way are monitors free? (Not challenging, just asking, as I haven't heard that assertion before.) Is it only from a performance point of view, or are there known VMs which also eliminate the space overhead? See JavaObjectOverheadIsRidiculous for more discussion of this concern. -- AdamBerger


The correct use of synchronized is important for performance. Putting it everywhere is silly. Here's an example:

 public synchronized void doSomething() {
   SomeObject? obj = getSomeObject();
   ... do something with obj that needs to be synchronized. ...
 }
The synchronized keyword is in the wrong place. It has placed a lock on the object containing the doSomething() method, when it should have been on obj. Strictly speaking, the contents of the method should be put into SomeObject?, and the synchronized keyword taken with it.

Synchronizing on the wrong object is a classic cause of Java performance problems.

It's important to note in the example above, though, that in certain VMs synchronizing a whole method is MUCH faster than using a synchronized blocks. This is one of the reasons java performance tuning is so difficult... not only are some VMs faster than others, but the relative speed of operations vary wildly. -- AdamBerger


It seems to me that (1) locking on any object is handy and (2) it isn't necessarily inefficient.

For the first point:

If I have an object that is shared between two threads, I might want to lock on it. If that object must implement Lockable to be locked, then any class which the designer forgot to make Lockable will need a Lockable wrapper. That introduces the inconvenience of delegating the functionality of the wrapped object, and of making sure that everything uses the Lockable wrapper rather than the unlockable object itself. Since every class you ever make might need to be lockable, every class should implement Lockable.

In my view, the question of whether or not a class is lockable is not up to the class designer: locking a class is arguably not an operation performed upon the class, but upon all references to the class. The class designer has no business dictating what may be done with references to the class.

For the second:

I think that setting breakpoints in code at the point where synchronisation needs to occur allows for synchronisation to be nearly free when it isn't being used. When it is being used, the overhead of having to wait for the lock to be released will probably greatly outweigh the slight hit from the breakpoint being triggered.

Although you can't set an infinite number of breakpoints for free (unless you use self-modifying code, which is icky and may not be allowed on all platforms anyway), for places where it matters it's the same breakpoint each time. My hardware supports at least 4 free breakpoints at a time, so if I'm in a tight loop which only references up to four potentially locked objects (such as arrays) I win every time.


It seems to me that (1) locking on any object is handy and (2) it isn't necessarily inefficient. I completely disagree with both statements. It's actually confusing when every object is a monitor - what exactly does the monitor protect? The object itself? The data structure hanging off of it? Which object of a data structure do I have to lock (synchronize) on to lock out other code that might change it while I'm accessing it? A method to selectively make objects of a class have a monitor (for example by the magic of implementing the magic 'Lockable' interface) provides a way to annotate source code about which objects are actually meant to be used as a monitor.

Only a few objects (i. e., objects of a few classes) need to act as monitors. Most likely, they are entry objects to data structures that are accessed by code run by different threads. Everything else, and that's the bulk of the objects created at run time, will never be subject to a 'synchronized' statement, and doesn't need to carry a monitor data structure around with it.


CategoryJava


EditText of this page (last edited November 13, 2006) or FindPage with title or text search