Почему нельзя синхронизировать абстрактный метод?

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

Это не имеет смысла, так как абстрактный класс является определением (контрактом) для дочернего класса. Абстрактное определение синхронизированного метода не нуждается в блокировке, это делает ребенок. Весь абстрактный заголовок будет указывать на то, что ребенок должны синхронизировать этот метод. Правильна ли моя логика? Если нет, может кто-нибудь объяснить, почему я ошибаюсь?

4 ответов


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

синхронизируется ли метод или нет, является детали реализации метода. Синхронизация не указана в любом месте как декларативный контракт-это не то, что вы можете синхронизировать в интерфейсах.

как класс реализует любые гарантии безопасности потока, которые он предоставляет, зависит от него. Если абстрактный класс хочет мандат определенный подход, он должен использовать шаблон метода шаблона:

// I hate synchronizing on "this"
private final Object lock = new Object();

public final void foo() {
    synchronized(lock) {
        fooImpl();
    }
}

protected abstract void fooImpl();

это довольно опасно само по себе, хотя, учитывая, что он эффективно вызывает "неизвестный" код в замке, рецепт тупики и т. д.


Извините, что это не имеет смысла, вот как это работает. Поведение блокировки не может быть указано с помощью абстрактных методов или методов интерфейса, оно не является частью контракта. Вероятно, идея состояла в том, что поведение блокировки является фундаментальной частью реализации-разные реализации захотят выполнять блокировку по-разному-и было бы чрезмерно указывать его на этом уровне абстракции.


synchronized void foo()
{
    body
}

определяется как эквивалентное

void foo()
{ 
    synchronized(this)
    {
        body
    }
}

(если статический, синхронизируется в классе вместо this)

поскольку абстрактный метод не имеет тела, synchronized ключевое слово метода не определено.


Я думаю, что одна из логик этого может заключаться в том, следует ли синхронизировать этот метод с помощью класса реализации. Это означает, что он дает свободу исполнителю выбирать, предоставлять ли синхронизированную или несинхронизированную реализацию. Кроме того, у клиента также будет возможность выбрать несинхронизированную версию, чтобы избежать накладных расходов на синхронизацию, если безопасность потоков не является проблемой.