Класс MutableCallSite

Прямые известные подклассы:
AbstractRelinkableCallSite
public class MutableCallSite
extends CallSite

MutableCallSite — это CallSite, чья переменная-цель ведет себя как обычное поле. Инструкция invokedynamic , связанная с MutableCallSite, делегирует все вызовы текущей цели сайта. Динамический вызывающий объект mutable call site также делегирует каждый вызов текущей цели сайта.

Вот пример mutable call site, который вводит переменную состояния в цепочку обработчиков методов.

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)

Один и тот же call site может использоваться сразу в нескольких местах.

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());

Несинхронизация значений целевых объектов: запись в целевой объект mutable call site не заставляет другие потоки узнать об обновлённом значении. Потоки, которые не выполняют соответствующие действия синхронизации относительно обновлённого call site, могут кэшировать старое значение целевого объекта и неопределённо откладывать использование нового значения целевого объекта. (Это нормальное следствие модели памяти Java, применительно к полям объектов.)

Операция syncAll предоставляет способ заставить потоки принять новое значение целевого объекта, даже если нет никакой другой синхронизации.

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

С:
1.7

Конструкторы

Конструктор Описание
MutableCallSite​(MethodHandle target)

Создаёт объект call site с начальным целевым обработчиком метода.

MutableCallSite​(MethodType type)

Создаёт пустой объект call site с заданным типом метода.

Методы

Модификатор и тип Метод Описание
MethodHandle getTarget()

Возвращает целевой метод call site, который ведёт себя как обычное поле MutableCallSite.

void setTarget​(MethodHandle newTarget)

Обновляет целевой метод этого call site, как обычную переменную.

static void syncAll​(MutableCallSite[] sites)

Выполняет операцию синхронизации для каждого call site в заданном массиве, заставляя все другие потоки отбросить любые кэшированные значения, ранее загруженные из целевого объекта любого из call site.

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

dynamicInvoker, 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()

syncAll

public static void syncAll(MutableCallSite[] sites)

Выполняет операцию синхронизации для каждого вызова в данном массиве, заставляя все другие нити отбросить любые кэшированные значения, ранее загруженные из целевого объекта любого из вызовов.

Эта операция не отменяет вызовы, которые уже начались со старым значением целевого объекта. (Java поддерживает переход во времени вперёд только.)

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

Чтобы избежать гонок, вызовы setTarget и syncAll обычно должны выполняться в рамках какой-либо взаимной блокировки. Обратите внимание, что нити-читатели могут наблюдать обновлённый целевой объект уже в тот момент, когда вызов setTarget устанавливает значение (и до вызова syncAll , который подтверждает значение). С другой стороны, нити-читатели могут наблюдать предыдущие версии целевого объекта до того, как вызов syncAll вернётся (и после вызова setTarget , который пытается передать обновлённую версию).

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

Если sites содержит элемент null, будет поднято исключение NullPointerException. В этом случае некоторые не-null элементы массива могут быть обработаны до того, как метод вернёт ошибку. Какие это элементы (если есть) зависит от реализации.

Детали модели памяти 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, 2020, 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/11/docs/api/java.base/java/lang/invoke/MutableCallSite.html

Spec-Zone .ru
спецификации, руководства, описания, API