Почему wait() и notify() не относятся к специальному классу?

Почему методы wait, notify и notifyAll помещены в Object, а не в какой-то отдельный класс?

Заметьте, этот вопрос не о переводе их в Thread класс, мне просто интересно, почему они засоряют Object, а не какой-то новый Monitor класс.

Я вижу следующие недостатки этой идеи:

  • Мы не сможем использовать наши поля для других целей в качестве мониторов. Но это, кажется, согласуется с принципом модульности.
  • Синхронизированные методы теперь потребуют некоторого взлома со сгенерированными скрытыми полями (например, в замыканиях), так как this и <MyClass>.class становятся недействительными мониторами.

Таким образом, мы могли бы удалить 5 методов из каждого объекта с небольшим горе. Или не?


person Martoon    schedule 16.02.2016    source источник
comment
I just wonder why does they litter Object, not some new Monitor class. - концептуально делают внутренне, но монитор уникален для каждого объекта. Смотрите дубликат ответа (хотя он относится к Thread)   -  person Andreas Fester    schedule 16.02.2016
comment
@biziclop Точно. Когда Пер Бринч Хансен увидел первоначальные конструкции параллелизма в Java, он написал: «Очевидно, что я работал напрасно». Похоже, что они были заимствованы из sleep/wakeup() непривлекательного внутреннего устройства UNIX.   -  person user207421    schedule 16.02.2016
comment
Таким образом, мы могли бы удалить 5 методов из каждого объекта с небольшим горем Насколько я знаю, технически эти методы существуют только один раз, а не один раз для каждого экземпляра.   -  person m0skit0    schedule 16.02.2016
comment
потому что Java не имеет множественного наследования, поэтому вы не можете тривиально смешивать эту функциональность   -  person Alnitak    schedule 16.02.2016
comment
m0skit0, Наверно, я неправильно сказал. Я имел в виду, что с точки зрения пользователя будет 5 дополнительных методов, что не очень удобно   -  person Martoon    schedule 16.02.2016
comment
Это можно рассматривать как дубликат (или, скорее, инверсию) stackoverflow.com/questions/1769489/   -  person Marco13    schedule 16.02.2016


Ответы (4)


Настоящим ответом является то, что это была ошибка, окончательно подтвержденная созданием Condition, который делает именно то, что вы ожидаете. (Хотя, поскольку это объект, есть вероятность, что вы случайно вызовете для него wait() вместо await(), что приведет к забавным последствиям...)

Помимо того, что вы уже перечислили, привязка монитора к каждому отдельному объекту также делает невозможным наличие действительно неизменяемых объектов в Java.

Итак, вы можете сделать это, например:

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

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

Возврат одного и того же целого числа в штучной упаковке для 42 каждый раз не должен быть проблемой, если объект неизменяемый. Но это не так, у него есть изменяемое состояние: его монитор, делающий возможным такую ​​синхронизацию. Что особенно плохо в этом, так это то, что вы создали мьютекс между двумя фрагментами кода, которые на первый взгляд кажутся независимыми.

person biziclop    schedule 16.02.2016
comment
Замечательный ответ. Я хотел добавить дополнительный +1, например, с кэшированием целых чисел. - person Martoon; 16.02.2016
comment
@Martoon В качестве упражнения я написал пару потоков ввода/вывода, которые используют это для связи друг с другом. Самое страшное то, что они будут работать везде, где вы поместите их в одну и ту же виртуальную машину, например, в два отдельных веб-приложения в одном контейнере. - person biziclop; 16.02.2016

Одним из преимуществ этого является то, что вы можете просто синхронизировать ссылку, не создавая для нее избыточный монитор:

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

vs

private final Object mySpecialMonitor = new Object();

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

Это не сработало бы, если бы вся синхронизация была в отдельном классе.

person AdamSkywalker    schedule 16.02.2016
comment
Да, это первый недостаток, который я перечислил. Но размышления таким образом приводят нас к переводу ReentrantLock.lock(), unlock(), StringBuilder.append(), я не знаю, что еще, в Object класс, что кажется не очень удачным поворотом. Я имею в виду, что класс Object не предназначен для синхронизации - person Martoon; 16.02.2016
comment
Я бы не назвал это преимуществом. Поскольку безопасный способ синхронизации не заключается в том, чтобы делать это на общедоступном объекте, большую часть времени вы все равно создаете выделенный объект блокировки в поле private final. - person biziclop; 16.02.2016

Потому что каждый объект может выступать в роли монитора.

person Grogi    schedule 16.02.2016
comment
Да, но вопрос в том, почему бы не иметь отдельный класс. - person m0skit0; 16.02.2016

1) Ожидание и уведомление - это не просто обычные методы или утилита синхронизации, более того, они являются механизмом связи между двумя потоками в Java. И класс Object - правильное место, чтобы сделать их доступными для каждого объекта, если этот механизм недоступен с помощью любого ключевого слова java, такого как synchronized. Помните, что синхронизация и уведомление об ожидании — это две разные области, и не путайте их с тем, что они одинаковы или связаны. Синхронизация предназначена для обеспечения взаимного исключения и обеспечения безопасности потока класса Java, такого как состояние гонки, в то время как ожидание и уведомление являются механизмом связи между двумя потоками.

2) Блокировки доступны для каждого объекта, что является еще одной причиной, по которой ожидание и уведомление объявляются в классе объектов, а не в классе потоков.

3) В Java, чтобы войти в критический раздел кода, потокам требуется блокировка, и они ждут блокировки, они не знают, какие потоки удерживают блокировку, вместо этого они просто знают, что блокировка удерживается каким-то потоком, и они должны ждать блокировки вместо зная, какой поток находится внутри синхронизированного блока, и попросив их снять блокировку. эта аналогия подходит для ожидания и уведомления в классе объектов, а не в потоке в Java.

со ссылкой: http://javarevisited.blogspot.in/2012/02/why-wait-notify-and-notifyall-is.html

person Harshil    schedule 16.02.2016