Класс 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 |
Создает объект сайта вызова с начальным дескриптором целевого метода. |
MutableCallSite |
Создает пустой объект сайта вызова с заданным типом метода. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
final MethodHandle |
dynamicInvoker() |
Создает дескриптор метода, эквивалентный инструкции invokedynamic, связанной с этим сайтом вызова. |
final MethodHandle |
getTarget() |
Возвращает целевой метод сайта вызова, который ведет себя как обычное поле MutableCallSite. |
void |
setTarget |
Обновляет целевой метод этого сайта вызова как обычную переменную. |
static void |
syncAll |
Выполняет операцию синхронизации для каждого сайта вызова в заданном массиве, заставляя все остальные потоки отбросить любые кэшированные значения, ранее загруженные из цели любого из сайтов вызова. |
Подробное описание конструкторов
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 с памятью аналогично чтению обычной переменной, например элемента массива или невольного нефинального поля.
В частности, текущий поток может повторно использовать результат предыдущего чтения цели из памяти и не заметить недавнее обновление цели другим потоком.
setTarget
public void setTarget(MethodHandle newTarget)
Взаимодействие с памятью аналогично записи в обычную переменную, например элемент массива или невольное нефинальное поле.
В частности, сторонние потоки могут не увидеть обновленную цель, пока не выполнят чтение из памяти. Более строгие гарантии можно обеспечить, добавив соответствующие операции в метод загрузки и/или целевые методы, используемые в данном сайте вызова.
- Переопределяет:
-
setTargetв классеCallSite - Параметры:
-
newTarget— новая цель - Исключения:
-
NullPointerException— если предлагаемая новая цель равна null -
WrongMethodTypeException— если тип метода предлагаемой новой цели отличается от типа предыдущей цели - См. также:
dynamicInvoker
public final MethodHandle dynamicInvoker()
Этот метод эквивалентен следующему коду:
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
© 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