Spec-Zone.ru › OpenJDK 17

Класс MutableCallSite

java.lang.Object
java.lang.invoke.CallSite
java.lang.invoke.MutableCallSite
Прямые известные подклассы:
AbstractRelinkableCallSite
public class MutableCallSite extends CallSite
Изменяемая ссылка на вызов — это CallSite, где целевая переменная ведет себя как обычное поле. Инструкция MutableCallSite, связанная с изменяемой ссылкой на вызов, делегирует все вызовы текущей цели сайта. Динамический вызывающий метод изменяемой ссылки на вызов также делегирует каждый вызов текущей цели сайта.

Вот пример изменяемой ссылки на вызов, которая вводит переменную состояния в цепочку обработчиков методов.


MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
MethodHandle MH_name = name.dynamicInvoker();
MethodType MT_str1 = MethodType.methodType(String.class);
MethodHandle MH_upcase = MethodHandles.lookup()
    .findVirtual(String.class, "toUpperCase", MT_str1);
MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
name.setTarget(MethodHandles.constant(String.class, "Rocky"));
assertEquals("ROCKY", (String) worker1.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Fred"));
assertEquals("FRED", (String) worker1.invokeExact());
// (mutation can be continued indefinitely)
 

Один и тот же сайт может использоваться сразу в нескольких местах.


MethodType MT_str2 = MethodType.methodType(String.class, String.class);
MethodHandle MH_cat = lookup().findVirtual(String.class,
  "concat", methodType(String.class, String.class));
MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
assertEquals("Fred, dear?", (String) worker2.invokeExact());
name.setTarget(MethodHandles.constant(String.class, "Wilma"));
assertEquals("WILMA", (String) worker1.invokeExact());
assertEquals("Wilma, dear?", (String) worker2.invokeExact());
 

Несинхронизация значений целевых объектов: Запись в целевой объект изменяемой ссылки на вызов не заставляет другие потоки узнать об обновленном значении. Потоки, которые не выполняют соответствующие синхронизирующие действия относительно обновленного сайта, могут кэшировать старое значение целевого объекта и неопределенно откладывать использование нового значения целевого объекта. (Это обычное следствие модели памяти Java, применяемой к полям объектов.)

Операция syncAll предоставляет способ заставить потоки принять новое значение целевого объекта, даже если нет другой синхронизации.

Для целевых значений, которые будут часто обновляться, рекомендуется использовать изменяемую ссылку на вызов со свойством volatile вместо неё.

С:
1.7

Краткое описание конструкторов

Конструктор Описание
MutableCallSite(MethodHandle target)
Создает объект ссылки на вызов с начальным целевым обработчиком метода.
MutableCallSite(MethodType type)
Создает пустой объект ссылки на вызов с заданным типом метода.

Краткое описание методов

Модификатор и тип Метод Описание
final MethodHandle dynamicInvoker()
Создает обработчик метода, эквивалентный инструкции invokedynamic, которая была связана с этим сайтом.
final MethodHandle getTarget()
Возвращает целевой метод ссылки на вызов, который ведет себя как обычное поле MutableCallSite.
void setTarget(MethodHandle newTarget)
Обновляет целевой метод этой ссылки на вызов, как обычную переменную.
static void syncAll(MutableCallSite[] sites)
Выполняет операцию синхронизации для каждого сайта вызова в заданном массиве, заставляя все другие потоки отбросить любые кэшированные значения, ранее загруженные из целевого объекта любого из сайтов вызова.

Методы, унаследованные от класса java.lang.invoke.CallSite

type

Методы, унаследованные от класса java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Подробное описание конструкторов

MutableCallSite

public MutableCallSite(MethodType type)
Создаёт пустой объект вызова с заданным типом метода. Начальный целевой объект задаётся в виде обработчика метода данного типа, вызов которого приведёт к исключению IllegalStateException, если он будет вызван.

Тип вызова устанавливается для данного объекта навсегда.

Прежде чем этот CallSite объект будет возвращён из метода инициализации или вызван каким-либо иным образом, ему обычно предоставляется более полезный целевой метод с помощью вызова setTarget.

Параметры:
type - тип метода, который будет иметь этот вызов
Исключения:
NullPointerException - если предложенный тип равен null

MutableCallSite

public MutableCallSite(MethodHandle target)
Создаёт объект вызова с начальным целевым обработчиком метода. Тип вызова устанавливается навсегда и соответствует типу начального целевого объекта.
Параметры:
target - обработчик метода, который будет являться начальным целевым объектом вызова
Исключения:
NullPointerException - если предложенный целевой объект равен null

Подробное описание методов

getTarget

public final MethodHandle getTarget()
Возвращает целевой метод вызова, который ведёт себя как обычное поле объекта MutableCallSite.

Взаимодействие getTarget с памятью такое же, как при чтении из обычной переменной, например, элемента массива или не-volatile, не-final поля.

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

Унаследованно от:
getTarget в классе CallSite
Возвращает:
состояние связывания этого вызова, обработчик метода, который может со временем меняться
См. также:
  • setTarget(java.lang.invoke.MethodHandle)

setTarget

public void setTarget(MethodHandle newTarget)
Обновляет целевой метод этого вызова, как обычную переменную. Тип нового целевого объекта должен совпадать с типом старого целевого объекта.

Взаимодействие с памятью такое же, как при записи в обычную переменную, например, элемент массива или не-volatile, не-final поле.

В частности, не связанные потоки могут не увидеть обновлённый целевой объект до тех пор, пока не выполнят чтение из памяти. Более сильные гарантии могут быть созданы путём помещения соответствующих операций в метод инициализации и/или целевые методы, используемые в каждом вызове.

Унаследованно от:
setTarget в классе CallSite
Параметры:
newTarget - новый целевой объект
Исключения:
NullPointerException - если предложенный новый целевой объект равен null
WrongMethodTypeException - если тип предложенного нового целевого объекта отличается от типа предыдущего целевого объекта
См. также:
  • getTarget()

dynamicInvoker

public final MethodHandle dynamicInvoker()
Создаёт обработчик метода, эквивалентный инструкции invokedynamic, которая была связана с этим вызовом.

Этот метод эквивалентен следующему коду:


 MethodHandle getTarget, invoker, result;
 getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class));
 invoker = MethodHandles.exactInvoker(this.type());
 result = MethodHandles.foldArguments(invoker, getTarget)
 
Унаследованно от:
dynamicInvoker в классе CallSite
Возвращает:
обработчик метода, который всегда вызывает текущий целевой объект этого вызова

syncAll

public static void syncAll(MutableCallSite[] sites)
Выполняет операцию синхронизации для каждого вызова в заданном массиве, заставляя все другие потоки отбросить любые кэшированные значения, ранее загруженные из целевого объекта любого из вызовов.

Эта операция не отменяет вызовы, которые уже начались со старым значением целевого объекта. (Java поддерживает путешествие вперёд во времени только.)

Общий эффект заключается в принудительном заставлянии всех будущих читателей целевого объекта каждого вызова принять наиболее недавно сохранённое значение. ("Наиболее недавно" определяется относительно самого syncAll.) И наоборот, вызов syncAll может заблокироваться до тех пор, пока все читатели (как-то) не удалят все предыдущие версии целевого объекта каждого вызова.

Для предотвращения гонок вызовы setTarget и syncAll обычно должны выполняться под какой-либо формой взаимной исключительности. Обратите внимание, что потоки-читатели могут наблюдать обновлённый целевой объект уже на стадии вызова setTarget который устанавливает значение (и до вызова syncAll, который подтверждает значение). С другой стороны, потоки-читатели могут наблюдать предыдущие версии целевого объекта до тех пор, пока вызов syncAll не вернётся (и после вызова setTarget, который пытается передать обновлённую версию).

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

Если sites содержит элемент null, будет поднято исключение NullPointerException. В этом случае некоторые не-null элементы массива могут быть обработаны до того, как метод вернёт исключение. Какие именно это элементы (если есть), зависит от реализации.

Подробности модели памяти Java

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

Видимые эффекты для каждого отдельного вызова S:

  • Создаётся новая volatile переменная V, и она записывается текущим потоком. Как определено в JMM, эта запись — глобальное событие синхронизации.
  • Как и обычно при локальном порядке событий записи в текущем потоке, каждое действие, уже выполненное текущим потоком, считается предшествующим volatile записи в V. (В некоторых реализациях это означает, что текущий поток выполняет глобальную операцию освобождения.)
  • В частности, запись в текущий целевой объект S считается предшествующей volatile записи в V.
  • Volatile запись в V размещается (специфическим для реализации способом) в глобальном порядке синхронизации.
  • Рассмотрим произвольный поток T (кроме текущего). Если T выполняет действие синхронизации A после volatile записи в V (в глобальном порядке синхронизации), то он должен увидеть либо текущий целевой объект S, либо более позднюю запись в этот целевой объект, если он выполняет чтение целевого объекта S. (Это ограничение называется "согласованностью порядка синхронизации".)
  • JMM специально разрешает компиляторам оптимизировать отбрасывание чтений или записей переменных, которые известны как бесполезные. Такие пропущенные чтения и записи не влияют на отношение happens-before. Несмотря на это, volatile V не будет пропущено, даже если его записанное значение неопределённо, и его прочитанное значение не используется.
Из-за последнего пункта реализация ведёт себя так, как будто поток T выполняет volatile чтение V сразу после своего действия A. В локальном порядке действий в T, это чтение происходит перед любым будущим чтением целевого объекта S. Будто реализация произвольно выбрала чтение целевого объекта V потоком T и принудила чтение S к предшествованию, тем самым обеспечив коммуникацию нового значения целевого объекта.

До тех пор, пока соблюдаются ограничения модели памяти Java, реализации могут задерживать завершение операции syncAll в то время, как другие потоки (T выше) продолжают использовать предыдущие значения целевого объекта S's target. Однако реализации, как и всегда, должны избегать тупика и в конечном итоге потребовать от всех потоков учесть обновлённый целевой объект.

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

Примечание по реализации: Простые реализации MutableCallSite могут использовать volatile переменную для целевого объекта mutable вызова. В такой реализации метод syncAll может быть пустым, и всё же он будет соответствовать поведению JMM, описанному выше.

Параметры:
sites - массив вызовов, которые нужно синхронизировать
Исключения:
NullPointerException - если ссылка на массив sites равна null или массив содержит null

© 1993, 2021, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/invoke/MutableCallSite.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API