Spec-Zone.ru › OpenJDK 21

Класс MutableCallSite

java.lang.Object
java.lang.invoke.CallSite
java.lang.invoke.MutableCallSite
Прямые известные подклассы:
AbstractRelinkableCallSite
public non-sealed class MutableCallSite extends CallSite
Переменная MutableCallSite — это CallSite, переменная цели которой ведет себя как обычное поле. Инструкция invokedynamic , связанная с 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 содержит нулевой элемент, будет выброшено исключение NullPointerException. В этом случае некоторые ненулевые элементы массива могут быть обработаны до аномального завершения метода. Какие именно элементы это будут (если таковые имеются) — зависит от реализации.

Подробности модели памяти 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. Это как если бы реализация произвольно выбрала чтение значения цели S потоком T и принудительно сделала чтение V предшествующим ему, тем самым гарантируя передачу нового значения цели.

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

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

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

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

© 1993, 2023, 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/21/docs/api/java.base/java/lang/invoke/MutableCallSite.html

Spec-Zone.ru

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