12

Why are wait, notify and notifyAll methods placed in Object, not in some separated class?

Note, this question is not about moving them to Thread class, I just wonder why does they litter Object, not some new Monitor class.

I see the following shortcomings of that idea:

  • We won't be able to use our for-other-purpose fields as monitors. But this seems to agree with principle of modularity.
  • Synchronized methods will now require some hack with generated hidden fields (like in closures), as this and <MyClass>.class become not valid monitors.

So we could move away 5 methods from every object with a little woe. Or not?

Martoon
  • 371
  • 1
  • 12
  • `I just wonder why does they litter Object, not some new Monitor class.` - conceptually, they do internally, but the monitor is unique for each object. See the duplicate answer (even though it refers to `Thread`) – Andreas Fester Feb 16 '16 at 11:38
  • 1
    @biziclop Exactly. When Per Brinch Hansen saw Java's initial concurrency constructs, he wrote 'clearly I have laboured in vain'. They seem to have been borrowed from the unlovely `sleep/wakeup()` internals of UNIX. – user207421 Feb 16 '16 at 11:45
  • *"So we could move away 5 methods from every object with a little woe"* AFAIK technically those methods only exist once, not once for each instance. – m0skit0 Feb 16 '16 at 11:47
  • 1
    because Java doesn't have multiple inheritance, so you can't trivially mixin that functionality – Alnitak Feb 16 '16 at 11:47
  • m0skit0, Surely, I said it wrong. I meant that in user's view would be 5 additional methods, which is not very convinient – Martoon Feb 16 '16 at 11:55
  • This could be considered as a "duplicate" (or rather the inverse of) http://stackoverflow.com/questions/1769489/why-are-wait-and-notify-declared-in-javas-object-class – Marco13 Feb 16 '16 at 12:10

3 Answers3

7

The real answer is that it was a mistake, finally acknowledged with the creation of the Condition class, which does exactly what you'd expect. (Although since it is an object, there is a possibility that you'll accidentally invoke wait() on it instead of await(), with hilarious consequences...)

Apart from the things you've already listed, tying a monitor to every single object also makes it impossible to have truly immutable objects in Java.

So you can do this for example:

class A {
   void foo() {
      synchronized((Integer)42) {
         ...
      }
   }
}

class B {
   void foo() {
      synchronized((Integer)42) { 
          ...
      }
   }
}

Returning the same boxed integer for 42 every time shouldn't be a problem if the object was immutable. But it isn't, it has a mutable state: its monitor, making this kind of synchronization possible. What's particularly evil in this is that you've created a mutex between two pieces of code that on the face of it appear to be independent.

biziclop
  • 48,926
  • 12
  • 77
  • 104
  • Remarkable answer. I wished to add extra +1 for example with caching Integers – Martoon Feb 16 '16 at 12:30
  • 1
    @Martoon As an exercise I wrote [a pair of input/output streams](http://pastebin.com/r2bKbXfE) that exploit this to communicate with each other. The really scary thing is that they will work wherever you put them in the same VM, two separate web apps in the same container for example. – biziclop Feb 16 '16 at 12:45
1

One advantage of this is that you can simply synchronize on a reference without creating a redundant monitor for it:

synchronized (myList) {
    myList.add(0);
}

vs

private final Object mySpecialMonitor = new Object();

syncronized(mySpecialMonitor) {
    myList.add(0);
}

It would not work if all synchronization was in a separate class.

AdamSkywalker
  • 11,408
  • 3
  • 38
  • 76
  • Yes, it's the first shortcoming I listed. But thinking in that way leads us to moving `ReentrantLock.lock()`, `unlock()`, `StringBuilder.append()`, I don't know what else, to `Object` class, which seems not to be a nice turn. I mean, `Object` class is not intended to be specialized for synchronizing – Martoon Feb 16 '16 at 12:38
  • 2
    I wouldn't call this an advantage. Since the safe way of synchronization is not to do it on a publicly visible object, most of the time you end up creating a dedicated lock object in a `private final` field anyway. – biziclop Feb 16 '16 at 13:00
0

Because every object can act as a monitor.

Grogi
  • 2,099
  • 17
  • 13