3

Recently, I was asked in interview why wait, notify, and notifyAll are used. I explained them.

After that they asked me to assume an application is always single threaded. Is it really required? My answer was no.

Then, they asked why is design like wait, notify, and notifyAll are methods on the Object class. Why doesn't Java have an interface and these methods are in that interface and which ever class wants to implement it can use it. So, I was kind of stuck and unable to think over this design. Can anyone please sow light over this?

Gray
  • 115,027
  • 24
  • 293
  • 354
Rahul Singh
  • 781
  • 11
  • 27
  • why implement them when they are already implemented? – user2717954 Mar 28 '17 at 14:40
  • wait/notify/notifyAll have already been refactored to an [interface](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/locks/Condition.html). See also [this post](http://stackoverflow.com/questions/4912165/whats-the-best-alternative-to-wait-notify-for-low-level-synchronization) – Roman Vottner Mar 28 '17 at 15:03
  • Possible duplicate of [Why are wait() and notify() declared in Java's Object class?](http://stackoverflow.com/questions/1769489/why-are-wait-and-notify-declared-in-javas-object-class) – Solomon Slow Mar 28 '17 at 20:45

4 Answers4

2

JVM uses OS-level threads. That means that each concrete JVM for each concrete OS handles threads differently. And these methods are not only implemented in Object class, they are marked as native, which kind of means that the are implemented in system layer of JVM.

And if those methods were in some interface, that would mean that anybody can redefine them.

esin88
  • 3,091
  • 30
  • 35
0

Wait and notify and notifyAll is not just normal methods or synchronization utility, more than that they are communication mechanism between two threads in Java. And Object class is correct place to make them available for every object if this mechanism is not available via any java keyword like synchronized. Remember synchronized and wait notify are two different area and don’t confuse that they are same or related. Synchronized is to provide mutual exclusion and ensuring thread safety of Java class like race condition while wait and notify are communication mechanism between two thread.

uday
  • 1
  • 3
0

Then, they asked why is design like wait, notify, and notifyAll are methods on the Object class. Why doesn't Java have an interface and these methods are in that interface and which ever class wants to implement it can use it.

All of these methods are implemented in native code and they integrate closely with the synchronized block that wraps them. They are part of the Java language definition and have specific behaviors that programmers rely on. It would not be appropriate for them just to be interface methods that any object would implement.

When one object calls obj.wait(); on another object, it doesn't have to worry about the implementation of wait. It needs to make sure that it has a mutex lock on that object so it can make critical updates to it or other storage and if the wait method was implemented by the object itself, then that object could violate the language requirements and, for example, allow multiple threads into the protected block at the same time. A thread can synchronize and call wait/notify/notifyAll on another object or not without having to worry about whether or not that object has implemented those methods appropriately. By making them final methods on Object the behavior will work the same regardless of the object type or local implementation.

Also, as I mentioned, wait/notify/notifyAll are integrated closely with the surrounding synchronized block. When a thread is blocked in wait() the surrounding synchronized lock is released so that other threads can get access to the protected block. This coordination would not be possible if the wait() was just a simple method call without other strange language features.

This reminds me of my other answer here: Concept behind putting wait(),notify() methods in Object class

Community
  • 1
  • 1
Gray
  • 115,027
  • 24
  • 293
  • 354
  • I would say that the consensus - at least in compiler circles - is that allowing every object to be used for synchronization was a costly mistake, particularly considering best practices for synchronization (use final object to make sure the lock can't be leaked). There's not many good arguments against providing an explicit lock class (an interface would indeed be a weird choice since there's only limited extensibility that makes sense) that enables these features really. Don't you agree? – Voo Mar 28 '17 at 21:16
  • Sorry but I don't agree. How is it "costly" if you don't have to use it? Everyone is so anti-`synchronized` when I'd rather the JVM be efficient at supporting it – maybe using the same `Lock` objects that people want to do by hand. I want to write and maintain less code and teach my junior programmers to use the language features instead of `Lock` objects directly unless I have to @Voo. – Gray Mar 28 '17 at 23:23
  • Because the JVM has to support locks in object headers for every single object despite only 0.0..01% of all objects will ever actually make use of it. Now HotSpot in particular goes to great lengths to minimize the associated overhead, but that complexity has costs of its own: There have been many intricate bugs in that part of the code. – Voo Mar 29 '17 at 08:12
  • And as I said best practice is to create a separate object just for locking anyhow. The difference between `private final Object lock = new Object()` and `private final Lock lock = new Lock()` is minimal at best, would clearly separate responsibilities, would avoid a source of bugs and bad design for beginners and would allow a great amount of customization. – Voo Mar 29 '17 at 08:15
  • Just because there is code supported by the JRE/JVM to create a lock per object doesn't mean that there is an impact on the object in memory @Voo. You don't get a monitor or a lock associated with the object unless you call `synchronized` on it. I can see a number of ways that it would be as expensive as `new Lock()` on demand. – Gray Mar 29 '17 at 16:39
  • The problem is that every object has to store at least one bit saying whether it needs a lock header or not *and* the space to actually store a pointer or index to the actual lock data structure. HotSpot reuses that space for other things (forward pointers during GC, hashcode), so after a good 20 years of optimisation at least the memory overhead has been reduced. That doesn't change the fact that the code juggling all those completely different things is incredibly complex and has been the source of many, many bugs and performance overhead during GC. – Voo Mar 29 '17 at 21:53
  • Seems like there is a lot of speculation there @Voo around how the JVM works. But maybe you've looked at more native code than I have. – Gray Mar 30 '17 at 12:41
  • Well the code is open source, so there's not really much speculation going on here: The starting point if you want to investigate would be [markOop.h](http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/oops/markOop.hpp) which describes the layout of an object header and some of the assumptions that have to hold. Now with regards to how many bugs there have been due to the additional complexities, that's certainly speculative, because that's hard to quantify. But I'm sure if you look at the code you'll agree that it's rather complex and that complexity attracts bugs. – Voo Mar 30 '17 at 18:51
0

It was a design goal from the start that Java programs would be multithreaded. Remember the plan was for Java to make embedded programming less intimidating, the whole serverside web application thing (leading to the commoditization of Sun's core business) was an accident.

Since the goal was to enable creating embedded applications that would talk to other devices, it had to be multithreaded in order to be network-friendly and event-driven. But writing efficient multithreaded servers wasn't high on the list for java.

Java didn't have ReentrantLock or nonblocking i/o for a long time. Initially the main data structures available were Vector, Hashtable, and StringBuffer (all of which had synchronized on all public methods). From that choice it seems like the goal was good-enough, as opposed to being as efficient as possible. Later on it was clear Java needed to be more efficient for the use case of server applications and 1.2 introduced equivalents of Vector and Hashtable that were unsynchronized. This seemed like an afterthought, a course adjustment made once it was apparent Java had a new role it wasn't previously designed for.

If Java had stayed in the niche it was created for then possibly intrinsic locks might have been adequate. It seems the initial plan was for intrinsic locks only, so that the lock might as well be wired into the Object.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276