Класс 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 |
Создаёт объект сайта вызовов с начальным дескриптором целевого метода. |
MutableCallSite |
Создаёт пустой объект сайта вызовов с указанным типом метода. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
final MethodHandle |
dynamicInvoker() |
Создаёт дескриптор метода, эквивалентный инструкции invokedynamic, связанной с этим сайтом вызовов. |
final MethodHandle |
getTarget() |
Возвращает целевой метод сайта вызовов, который ведёт себя как обычное поле MutableCallSite. |
void |
setTarget |
Обновляет целевой метод этого сайта вызовов как обычную переменную. |
static void |
syncAll |
Выполняет операцию синхронизации для каждого сайта вызовов в указанном массиве, заставляя все остальные потоки отбросить любые кэшированные значения, ранее загруженные из цели любого из этих сайтов вызовов. |
Методы, объявленные в классе CallSite
type | Модификатор и тип | Метод | Описание |
|---|---|---|
MethodType |
type() |
Возвращает тип цели этого сайта вызовов. |
Методы, объявленные в классе Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait | Модификатор и тип | Метод | Описание |
|---|---|---|
protected Object |
clone() |
Создаёт и возвращает копию этого объекта. |
boolean |
equals |
Показывает, равен ли какой-либо другой объект этому объекту. |
protected void |
finalize() |
Устарел, будет удалён: этот элемент API подлежит удалению в будущей версии. Финализация устарела и подлежит удалению в одном из будущих выпусков. |
final Class |
getClass() |
Возвращает класс времени выполнения этого Object. |
int |
hashCode() |
Возвращает хеш-код этого объекта. |
final void |
notify() |
Пробуждает один поток, ожидающий на мониторе этого объекта. |
final void |
notifyAll() |
Пробуждает все потоки, ожидающие на мониторе этого объекта. |
String |
toString() |
Возвращает строковое представление объекта. |
final void |
wait() |
Заставляет текущий поток ожидать пробуждения, обычно посредством вызова notify или interrupt. |
final void |
wait |
Заставляет текущий поток ожидать пробуждения, обычно посредством вызова notify или interrupt, либо до истечения заданного интервала реального времени. |
final void |
wait |
Заставляет текущий поток ожидать пробуждения, обычно посредством вызова notify или interrupt, либо до истечения заданного интервала реального времени. |
Подробное описание конструкторов
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.
В частности, текущий поток может повторно использовать результат предыдущего чтения цели из памяти и может не увидеть недавнее обновление цели, выполненное другим потоком.
setTarget
public void setTarget(MethodHandle newTarget)
Взаимодействие с памятью такое же, как при записи обычной переменной, например элемента массива или поля, не являющегося volatile или final.
В частности, несвязанные потоки могут не увидеть обновлённую цель, пока не выполнят чтение из памяти. Более строгие гарантии можно обеспечить, добавив соответствующие операции в метод начальной загрузки и/или целевые методы, используемые в данном сайте вызовов.
- Переопределяет:
-
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 эта операция выполняет действие синхронизации, эффект которого сопоставим с записью volatile-переменной текущим потоком и последующим чтением volatile-переменной каждым другим потоком, который может обращаться к одному из затронутых сайтов вызовов. Для каждого отдельного сайта вызовов S очевидны следующие эффекты:
- Создаётся новая volatile-переменная
V, в которую выполняет запись текущий поток. Согласно JMM, эта запись является глобальным событием синхронизации. - Как обычно при упорядочивании событий записи в потоке, считается, что каждое действие, уже выполненное текущим потоком, происходит до volatile-записи в
V. (В некоторых реализациях это означает, что текущий поток выполняет глобальную операцию освобождения.) - В частности, запись текущей цели
Sсчитается происходящей до volatile-записи вV. - Volatile-запись в
Vпомещается (зависящим от реализации способом) в глобальный порядок синхронизации. - Рассмотрим произвольный поток
T(не являющийся текущим потоком). ЕслиTвыполняет действие синхронизацииAпосле volatile-записи вV(в глобальном порядке синхронизации), то при чтении целиSон обязан увидеть текущую цельSили более позднюю запись в эту цель. (Это ограничение называется «согласованностью порядка синхронизации».) - JMM прямо разрешает оптимизирующим компиляторам исключать чтения или записи переменных, заведомо не имеющие смысла. Такие исключённые чтения и записи не влияют на отношение «происходит до». Несмотря на это, volatile-переменная
Vне будет исключена, хотя записываемое в неё значение неопределённо, а прочитанное значение не используется.
T выполнял volatile-чтение V непосредственно после своего действия A. В локальном порядке действий T это чтение происходит до любого последующего чтения цели S. Это равносильно тому, как если бы реализация произвольно выбрала чтение цели S потоком T и заставила чтение V предшествовать ему, тем самым обеспечив передачу нового значения цели. Пока соблюдаются ограничения модели памяти Java, реализации могут задерживать завершение операции syncAll, в то время как другие потоки (T выше) продолжают использовать предыдущие значения цели S. Однако реализации (как и всегда) рекомендуется избегать livelock и в конечном итоге обеспечить учёт обновлённой цели всеми потоками.
Обсуждение: Из соображений производительности syncAll является не виртуальным методом для одного сайта вызовов, а применяется к набору сайтов вызовов. В некоторых реализациях обработка одной или нескольких операций синхронизации может иметь большие фиксированные накладные расходы, но небольшие дополнительные расходы для каждого последующего сайта вызовов. В любом случае эта операция, вероятно, будет затратной, поскольку для того, чтобы другие потоки заметили обновлённое значение цели, их, возможно, придётся каким-либо образом прервать. Однако следует учитывать, что один вызов для синхронизации нескольких сайтов имеет тот же формальный эффект, что и множество вызовов, каждый из которых применяется только к одному сайту.
Примечание по реализации: Простые реализации MutableCallSite могут использовать volatile-переменную для цели изменяемого сайта вызовов. В такой реализации метод 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.