В Java 8 я могу легко написать:
interface Interface1 {
default void method1() {
synchronized (this) {
// Something
}
}
static void method2() {
synchronized (Interface1.class) {
// Something
}
}
}
Я получу полную семантику синхронизации, которую я могу использовать и в классах. Однако я не могу использовать synchronized
модификатор в объявлениях методов:
interface Interface2 {
default synchronized void method1() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
static synchronized void method2() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
}
Теперь можно утверждать , что два интерфейса ведут себя таким же образом , за исключением того, что Interface2
устанавливает контракт на method1()
и на method2()
, что немного сильнее , чем Interface1
делает. Конечно, мы могли бы также утверждать, что default
реализации не должны делать никаких предположений о конкретном состоянии реализации, или что такое ключевое слово просто не будет тянуть свой вес.
Вопрос:
По какой причине экспертная группа JSR-335 решила не поддерживать synchronized
методы интерфейса?
java
java-8
synchronized
default-method
jsr335
Лукас Эдер
источник
источник
default synchronized
, но не обязательно для негоstatic synchronized
, хотя я бы согласился, что последнее могло быть опущено по соображениям согласованности.synchronized
модификатор может быть переопределен в подклассах, следовательно, это будет иметь значение только в том случае, если есть что-то в качестве окончательных методов по умолчанию. (Ваш другой вопрос)synchronized
в суперклассах, эффективно удаляя синхронизацию. Я не удивлюсь, что не поддержкаsynchronized
и не поддержкаfinal
связаны, хотя, может быть, из-за множественного наследования (например, наследованиеvoid x()
иsynchronized void x()
т. Д.). Но это предположение. Мне любопытно по поводу авторитетной причины, если она есть.super
что требует полной повторной реализации и возможного доступа к закрытым членам. Кстати, есть причина, по которой эти методы называются «защитниками» - они присутствуют, чтобы облегчить добавление новых методов.Ответы:
Хотя на первый взгляд может показаться очевидным, что кто-то захочет поддерживать
synchronized
модификатор в методах по умолчанию, оказывается, что это будет опасно и поэтому запрещено.Синхронизированные методы - это сокращение для метода, который ведет себя так, как будто все тело заключено в
synchronized
блок, чей объект блокировки является получателем. Может показаться целесообразным расширить эту семантику и на методы по умолчанию; в конце концов, они тоже являются экземплярами методов с получателем. (Обратите внимание, чтоsynchronized
методы являются полностью синтаксической оптимизацией; они не нужны, они просто более компактны, чем соответствующийsynchronized
блок. Есть разумный аргумент, чтобы, во-первых, это была преждевременная синтаксическая оптимизация, и что синхронизированные методы вызывают больше проблем, чем решают, но этот корабль давно отплыл.)Итак, почему они опасны? Синхронизация о блокировке. Блокировка - это координация общего доступа к изменяемому состоянию. Каждый объект должен иметь политику синхронизации, которая определяет, какие блокировки защищают, какие переменные состояния. (См. Java Concurrency на практике , раздел 2.4.)
Многие объекты используют в качестве своей политики синхронизации шаблон монитора Java (JCiP 4.1), в котором состояние объекта защищается его внутренней блокировкой. В этом шаблоне нет ничего волшебного или особенного, но он удобен, и использование
synchronized
ключевого слова для методов неявно предполагает этот шаблон.Это класс, которому принадлежит состояние, которое определяет политику синхронизации этого объекта. Но интерфейсам не принадлежит состояние объектов, в которые они смешаны. Поэтому использование синхронизированного метода в интерфейсе предполагает определенную политику синхронизации, но такую, которую у вас нет разумных оснований для принятия, поэтому вполне может быть так, что использование синхронизации не обеспечивает никакой дополнительной безопасности потока (вы можете синхронизироваться с неправильной блокировкой). Это даст вам ложное чувство уверенности в том, что вы что-то сделали с безопасностью потоков, и ни одно сообщение об ошибке не сообщит вам, что вы принимаете неправильную политику синхронизации.
Уже достаточно сложно постоянно поддерживать политику синхронизации для одного исходного файла; еще труднее обеспечить, чтобы подкласс правильно придерживался политики синхронизации, определенной его суперклассом. Попытка сделать это между такими слабо связанными классами (интерфейсом и, возможно, многими классами, которые его реализуют) была бы почти невозможной и подверженной ошибкам.
Учитывая все эти аргументы против, для чего будет аргумент? Кажется, они в основном делают интерфейсы более похожими на черты. Хотя это понятное желание, центром разработки методов по умолчанию является развитие интерфейса, а не «черты». В тех случаях, когда эти два фактора могли быть последовательно достигнуты, мы стремились к этому, но там, где одно находится в конфликте с другим, нам приходилось выбирать в пользу основной цели проектирования.
источник
synchronized
модификатор метода появился в выводе javadoc, вводя людей в заблуждение, что он является частью спецификации. Это было исправлено в JDK 1.2. Даже если он появляется в открытом методе,synchronized
модификатор является частью реализации, а не контракта. (Подобное рассуждение и обработка произошли дляnative
модификатора.)synchronized
и создавать потоки безопасных компонентов, и у вас была почти поточно-безопасная программа. Проблема была в том, что это обычно работало нормально, но ломалось удивительными и хрупкими способами. Я согласен, что понимание того, как работает ваша блокировка, является ключом к надежным приложениям.synchronized(this) {...}
разрешено вdefault
методе? (Как показано в вопросе Лукаса.) Разве это не позволяет методу по умолчанию владеть состоянием класса реализации? Разве мы не хотим предотвратить это тоже? Нам понадобится правило FindBugs, чтобы найти случаи, для которых неосведомленные разработчики делают это?synchronized(vector)
. Если вы хотите быть в безопасности, вы никогда не должны использовать публичный объект (такой как онthis
сам) для блокировки.результат:
(извините за использование родительского класса в качестве примера)
Исходя из этого, мы могли бы знать, что блокировка родительского класса принадлежит каждому подклассу, объекты SonSync1 и SonSync2 имеют различную блокировку объекта. каждый замок независим. так что в этом случае, я думаю, не опасно использовать синхронизированный в родительском классе или общий интерфейс. Кто-нибудь может объяснить больше об этом?
источник