tags:

views:

503

answers:

4

Every Java Object has the methods wait() and notify() (and additional variants). I have never used these and I suspect many others haven't. Why are these so fundamental that every object has to have them and is there a performance hit in having them (presumably some state is stored in them)?

EDIT to emphasize the question. If I have a List<Double> with 100,000 elements then every Double has these methods as it is extended from Object. But it seems unlikely that all of these have to know about the threads that manage the List.

EDIT excellent and useful answers. @Jon has a very good blog post which crystallised my gut feelings. I also agree completely with @Bob_Cross that you should show a performance problem before worrying about it. (Also as the nth law of successful languages if it had been a performance hit then Sun or someone would have fixed it).

A: 

These methods are around to implement inter-thread communication.

Check this article on the subject.

Rules for those methods, taken from that article:

  • wait( ) tells the calling thread to give up the monitor and go to sleep until some other thread enters the same monitor and calls notify( ).
  • notify( ) wakes up the first thread that called wait( ) on the same object.
  • notifyAll( ) wakes up all the threads that called wait( ) on the same object. The highest priority thread will run first.

Hope this helps...

KB22
They don't do inter-*process* communication - they do inter-*thread* co-ordination.
Jon Skeet
thx for correcting.
KB22
There. Corrected.
Tom Hawtin - tackline
+16  A: 

Well, it does mean that every object has to potentially have a monitor associated with it. The same monitor is used for synchronized. If you agree with the decision to be able to synchronize on any object, then wait() and notify() don't add any more per-object state. The JVM may allocate the actual monitor lazily (I know .NET does) but there has to be some storage space available to say which monitor is associated with the object. Admittedly it's possible that this is a very small amount (e.g. 3 bytes) which wouldn't actually save any memory anyway due to padding of the rest of the object overhead - you'd have to look at how each individual JVM handled memory to say for sure.

Note that just having extra methods doesn't affect performance (other than very slightly due to the code obvious being present somewhere). It's not like each object or even each type has its own copy of the code for wait() and notify(). Depending on how the vtables work, each type may end up with an extra vtable entry for each inherited method - but that's still only on a per type basis, not a per object basis. That's basically going to get lost in the noise compared with the bulk of the storage which is for the actual objects themselves.

Personally, I feel that both .NET and Java made a mistake by associating a monitor with every object - I'd rather have explicit synchronization objects instead. I wrote a bit more on this in a blog post about redesigning java.lang.Object/System.Object.

Jon Skeet
@Jon thanks - this was also my take on it.
peter.murray.rust
+2  A: 

All objects in Java have monitors associated with them. Synchronization primitives are useful in pretty much all multi-threaded code, and its semantically very nice to synchronize on the object(s) you are accessing rather than on separate "Monitor" objects.

Java may allocate the Monitors associated with the objects as needed - as .NET does - and in any case the actual overhead for simply allocating (but not using) the lock would be quite small.

In short: its really convenient to store Objects with their thread safety support bits, and there is very little performance impact.

Kevin Montrose
I don't think it's actually that convenient - best practice recommends that you encapsulate locks by not exposing them outside your class unless you need to anyway (e.g. don't lock on "this" or "Foo.class"). It would be more elegant *and* slightly more storage-efficient not to have a monitor potentially associated with each class.
Jon Skeet
Ehhh... if you're regularly exposing fields from a class you have issues aside from locking efficiency. I do agree that you could save some memory by explicitly declaring lock objects, but that should be on the order of sizeof(void*) or sizeof(int) per-object (assuming lazy initialization); if you're __that__ concerned you probably shouldn't be linking in a runtime as large as the JVM.
Kevin Montrose
+6  A: 

Why are these so fundamental that every object has to have them and is there a performance hit in having them (presumably some state is stored in them)?

tl;dr: They are thread-safety methods and they have small costs relative to their value.

The fundamental realities that these methods support are that:

  1. Java is always multi-threaded. Example: check out the list of Threads used by a process using jconsole or jvisualvm some time.
  2. Correctness is more important than "performance." When I was grading projects (many years ago), I used to have to explain "getting to the wrong answer really fast is still wrong."

Fundamentally, these methods provide some of the hooks to manage per-Object monitors used in synchronization. Specifically, if I have synchronized(objectWithMonitor) in a particular method, I can use objectWithMonitor.wait() to yield that monitor (e.g., if I need another method to complete a computation before I can proceed). In that case, that will allow one other method that was blocked waiting for that monitor to proceed.

On the other hand, I can use objectWithMonitor.notifyAll() to let Threads that are waiting for the monitor that I am going to be relinquishing the monitor soon. They can't actually proceed until I leave the synchronized block, though.

With respect to specific examples (e.g., long Lists of Doubles) where you might worry that there's a performance or memory hit on the monitoring mechanism, here are some points that you should likely consider:

  1. First, prove it. If you think there is a major impact from a core Java mechanism such as multi-threaded correctness, there's an excellent chance that your intuition is false. Measure the impact first. If it's serious and you know that you'll never need to synchronize on an individual Double, consider using doubles instead.
  2. If you aren't certain that you, your co-worker, a future maintenance coder (who might be yourself a year later), etc., will never ever ever need a fine granularity of theaded access to your data, there's an excellent chance that taking these monitors away would only make your code less flexible and maintainable.

Follow-up in response to the question on per-Object vs. explicit monitor objects:

Short answer: Explicit external locks and monitors are already available in Java if you would like to use them (and you can use these methods to do so). Taking the internal monitors away would only remove easily accessible safety from the software engineer's hands.

My feeling is that synchronized, wait and notifyAll can be used to implement naive (in the sense of simple, accessible but perhaps not bleeding-edge performance) thread-safety. The canonical example would be one of these Doubles (posited by the OP) which can have one Thread set a value while the AWT thread gets the value to put it on a JLabel. In that case, there is no good reason to create an explicit additional Object just to have an external monitor.

At a slightly higher level of complexity, these same methods are useful as an external monitoring method. In the example above, I explicitly did that (see objectWithMonitor fragments above). Again, these methods are really handy for putting together relatively simple thread safety.

If you would like to be even more sophisticated, I think you should seriously think about reading Java Concurrency In Practice (if you haven't already). Read and write locks are very powerful without adding too much additional complexity.

Punchline: Using basic synchronization methods, you can exploit a large portion of the performance enabled by modern multi-core processors with thread-safety and without a lot of overhead.

Bob Cross
+1 for "First, prove it." :)
Aaron Digulla
@Aaron Digulla, thanks - personally, I think that should be the first sentence in any performance argument.
Bob Cross
While I agree with all the advice here, I don't see any connection between these being fundamentally important bits of functionality, and them being fundamental *to every object*. In other words, would any of this answer not work if you had to use a separate object for the monitor?
Jon Skeet