Ссылочная аннотация на поле пакета

#java #multithreading #osgi #declarative-services

#java #многопоточность #osgi #декларативный-сервисы

Вопрос:

Я разрабатываю приложение с OSGi. Заглядывая в OSGi compendium 6.0 (раздел 112.8.1) , я наткнулся на декларативный сервис; в частности, я просмотрел следующий абзац:

Для поля по умолчанию для ссылочной аннотации являются:

  • Имя метода или поля привязки используется для имени ссылки.
  • количество элементов 1: 1, если поле не является коллекцией. количество элементов 0 ..n, если поле является коллекцией.
  • Статическая политика отказа, если поле не объявлено изменяемым. Динамическая политика отказа, если поле объявлено изменчивым
  • Запрашиваемая услуга — это тип поля.

Например:

 @Reference
volatile Collection<LogService> log;
  

Теперь я прочитал из книги Нила Бартлетта OSGi in practice (раздел 11.10.2), что синхронизация и параллелизм методов bind и unbind Reference annotation немного сложны (особенно в сценариях динамической политики). В частности, потокобезопасным примером ссылки на службу через аннотацию может быть:

 @Component( provide = MailboxListener.class, properties = { "service.ranking = 10"})
public class LogMailboxListener implements MailboxListener {
    private final AtomicReference<Log> logRef = newAtomicReference <Log> () ;

    public void messagesArrived ( String mboxName, Mailbox mbox, long [ ] ids ) {
        Log log = logRef.get();
        if (log != null ) 
            log.log(Log.INFO, ids.length   "message(s) arrived in mailbox "   mboxName, null);
        else
            System.err.println("No log available!");
    }

    @Reference( service = Log.class, dynamic = true, optional = true )
    public void setLog(Log log) {
        logRef.set(log);
    }

    public void unsetLog(Log log) {
        logRef.compareAndSet(log, null);
    }
}
  

Я думаю, что понял из книги, почему динамическая политика нуждается в этих корректировках из многопоточного сценария. Мой вопрос: если ссылочная аннотация была в поле (декларативный сервис 1.3), как я мог бы достичь потокобезопасности? Только путем определения ссылки как «изменчивой» (как предлагает сборник)? Или есть какая-то сложная часть, которая создаст проблемы в приложении?

Спасибо за любой любезный ответ

Ответ №1:

Когда вы используете динамическую ссылку политики на поле, поле должно быть изменяемым. В вашем примере каждый раз, когда изменяется набор LogServices, в поле вводится новая коллекция. Таким образом, это будет безопасно, поскольку, если ваш код повторяет старую коллекцию, старая коллекция остается неизменной. Когда ваш код вернется к полю журнала, он увидит новую коллекцию.

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

Комментарии:

1. Итак, чтобы использовать аннотированную полем ссылку на пакет, мне нужно, всякий раз, когда мне нужно использовать саму ссылку, использовать само поле (а не локальную копию, подобную LogService a = this.log )? Позвольте мне привести пример (для простоты я буду использовать простой LogService вместо их набора): public void foo() { if (this.log != null) { this.log.log("foo started"); //do other code } Является ли это потокобезопасным, если для log поля просто установлено значение volatile? Или мне нужны дополнительные операции?

2. Когда вам когда-либо понадобится использовать logservice, скопируйте его в локальную переменную из поля, используйте локальную переменную, а затем позвольте локальной переменной выйти из области видимости. Моя цель заключалась не в том, чтобы скопировать ее из поля в какое-то другое местоположение, которое хранится в течение длительного времени (например, другой объект).

3. @BJHargave Ах, хорошо, теперь я понимаю! Я прочитал на практике точно такую же процедуру, которую вы только что написали в OSGi Нила, но из вашего комментария я ошибочно подумал, что вы предложили избегать использования локальной переменной. Теперь все совершенно ясно! Я опасался, что написание потокобезопасных ссылок на службы отличалось использованием аннотированного поля, но, по-видимому, все намного проще! Мне даже не нужны AtomicReference или проверки null внутри метода unbind. Похоже, что современные ссылки на OSGi должны использовать как можно больше аннотированных полем версий DS, а не метод bind / unbind, верно?

4. В той мере, в какой вашей компонентной реализации не требуется уведомление об изменениях в связанных службах (как вы получили бы при вызовах методов bind и unbind), тогда да, использование ссылок на поля намного проще и менее подвержено ошибкам в использовании.