Spec-Zone.ru › OpenJDK 25

Класс 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 позволяет принудительно обеспечить принятие потоками нового значения цели, даже если никакой другой синхронизации нет.

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

С момента:
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)
Выполняет операцию синхронизации для каждого сайта вызова в заданном массиве, заставляя все остальные потоки отбросить любые кэшированные значения, ранее загруженные из цели любого из сайтов вызова.

Методы, объявленные в классе CallSite

type

Методы, объявленные в классе 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 с памятью аналогично чтению обычной переменной, например элемента массива или невольного нефинального поля.

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

Переопределяет:
getTarget в классе CallSite
Возвращает:
состояние связи этого сайта вызова — дескриптор метода, который может изменяться со временем
См. также:
  • setTarget(MethodHandle)

setTarget

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

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

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

Переопределяет:
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. В этом случае некоторые ненулевые элементы массива могут быть обработаны до того, как метод завершится аварийно. Какие именно элементы (если таковые имеются) будут обработаны, зависит от реализации.

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

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

Для каждого отдельного сайта вызова S проявляются следующие эффекты:

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

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

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

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

Параметры:
sites — массив сайтов вызова для синхронизации
Исключения:
NullPointerException — если ссылка на массив sites равна null или массив содержит null

Сообщить об ошибке или предложить улучшение
Дополнительные справочные материалы по API и документацию для разработчиков см. в документации Java SE, содержащей более подробные описания для разработчиков с концептуальными обзорами, определениями терминов, обходными решениями и рабочими примерами кода. Другие версии.
Java является товарным знаком или зарегистрированным товарным знаком Oracle и/или ее аффилированных лиц в США и других странах.
Авторское право © 1993, 2025, Oracle и/или ее аффилированные лица, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
Все права защищены. Использование регулируется условиями лицензии и политикой распространения документации.

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

Spec-Zone.ru

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