Spec-Zone.ru › OpenJDK 24

Класс MutableCallSite

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

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

Обсуждение: По причинам производительности, 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.
https://download.java.net/java/early_access/jdk24/docs/api/java.base/java/lang/invoke/MutableCallSite.html

Spec-Zone.ru

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