Класс SwitchPoint
public class SwitchPoint extends Object
Объект, который может публиковать переходы состояний в другие потоки. Переключатель (switch point) изначально находится в состоянии valid, но может в любое время быть изменён на состояние invalid. Отменить аннулирование невозможно. Переключатель может объединить защищённую пару обработчиков методов в защищённого делегата. Защищённый делегат — это обработчик методов, который делегирует одному из старых обработчиков методов. Состояние переключателя определяет, какой из двух получает делегирование.
Один переключатель может использоваться для управления любым количеством обработчиков методов. (Косвенно, следовательно, он может управлять любым количеством мест вызова.) Это делается путём использования единственного переключателя в качестве фабрики для объединения любого количества пар защищённых обработчиков методов в защищённых делегатов.
Когда защищённый делегат создаётся из защищённой пары, пара упаковывается в новый обработчик методов M, который постоянно ассоциируется с переключателем, который его создал. Каждая пара состоит из целевого обработчика T и резервного F. Пока переключатель имеет состояние valid, вызовы к M делегируются T. После того, как он аннулирован, вызовы делегируются F.
Аннулирование является глобальным и мгновенным, как если бы переключатель содержал переменную volatile boolean, используемую при каждом вызове M. Аннулирование также является постоянным, что означает, что переключатель может изменить состояние только один раз. Переключатель всегда будет делегировать F после аннулирования. В этот момент guardWithTest может игнорировать T и вернуть F.
Вот пример работы переключателя:
MethodHandle MH_strcat = MethodHandles.lookup()
.findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
SwitchPoint spt = new SwitchPoint();
assert(!spt.hasBeenInvalidated());
// the following steps may be repeated to re-use the same switch point:
MethodHandle worker1 = MH_strcat;
MethodHandle worker2 = MethodHandles.permuteArguments(MH_strcat, MH_strcat.type(), 1, 0);
MethodHandle worker = spt.guardWithTest(worker1, worker2);
assertEquals("method", (String) worker.invokeExact("met", "hod"));
SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
assert(spt.hasBeenInvalidated());
assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
Обсуждение: Переключатели полезны без наследования. Их также можно наследовать. Это может быть полезно для того, чтобы ассоциировать логику аннулирования, специфичную для приложения, с переключателем. Обратите внимание, что нет постоянной связи между переключателем и обработчиками методов, которые он создаёт и использует. Сборщик мусора может собирать обработчики методов, созданные или используемые переключателем, независимо от срока службы самого переключателя.
Примечание об реализации: Переключатель ведёт себя так, как будто он реализован поверх MutableCallSite, примерно следующим образом:
public class SwitchPoint {
private static final MethodHandle
K_true = MethodHandles.constant(boolean.class, true),
K_false = MethodHandles.constant(boolean.class, false);
private final MutableCallSite mcs;
private final MethodHandle mcsInvoker;
public SwitchPoint() {
this.mcs = new MutableCallSite(K_true);
this.mcsInvoker = mcs.dynamicInvoker();
}
public MethodHandle guardWithTest(
MethodHandle target, MethodHandle fallback) {
// Note: mcsInvoker is of type ()boolean.
// Target and fallback may take any arguments, but must have the same type.
return MethodHandles.guardWithTest(this.mcsInvoker, target, fallback);
}
public static void invalidateAll(SwitchPoint[] spts) {
List<MutableCallSite> mcss = new ArrayList<>();
for (SwitchPoint spt : spts) mcss.add(spt.mcs);
for (MutableCallSite mcs : mcss) mcs.setTarget(K_false);
MutableCallSite.syncAll(mcss.toArray(new MutableCallSite[0]));
}
}
- Since:
- 1.7
Краткое описание конструкторов
| Конструктор | Описание |
|---|---|
SwitchPoint() |
Создаёт новый переключатель. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
MethodHandle |
guardWithTest |
Возвращает обработчик метода, который всегда делегирует либо целевому, либо резервному обработчику. |
boolean |
hasBeenInvalidated() |
Определяет, был ли этот переключатель аннулирован. |
static void |
invalidateAll |
Устанавливает все заданные переключатели в состояние invalid. |
Подробное описание конструкторов
SwitchPoint
public SwitchPoint()
Подробное описание методов
hasBeenInvalidated
public boolean hasBeenInvalidated()
Обсуждение: Из-за односторонней природы аннулирования, как только переключатель начинает возвращать true для hasBeenInvalidated, он всегда будет делать это в будущем. С другой стороны, видимый другим потокам переключатель в состоянии valid может быть аннулирован в любой момент из-за запроса другого потока.
Поскольку аннулирование является глобальной и мгновенной операцией, выполнение этого запроса на переключателе в состоянии valid должно быть внутренне согласовано со всеми другими потоками, которые могут вызвать аннулирование. Поэтому этот запрос может быть дорогим. Рекомендуемый способ построения обработчика методов с булевым значением, который запрашивает состояние аннулирования переключателя s — это вызов s.guardWithTest для обработчиков методов constant true и false.
- Возвращает:
- true, если этот переключатель был аннулирован
guardWithTest
public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback)
Целевой и резервный обработчики должны быть одного и того же типа метода, и результирующий объединённый обработчик метода также будет иметь этот тип.
- Параметры:
-
target- обработчик метода, выбираемый переключателем, пока он имеет состояние valid -
fallback- обработчик метода, выбираемый переключателем после аннулирования - Возвращает:
- объединённый обработчик метода, который всегда вызывает либо целевой, либо резервный обработчик
- Исключения:
-
NullPointerException- если любой из аргументов равен null -
IllegalArgumentException- если типы двух обработчиков не совпадают - См. также:
invalidateAll
public static void invalidateAll(SwitchPoint[] switchPoints)
Эта операция может быть дорогостоящей и должна использоваться с осторожностью. Если возможно, она должна быть буферизована для пакетной обработки набора переключателей.
Если switchPoints содержит нулевой элемент, будет вызвано исключение NullPointerException. В этом случае некоторые ненулевые элементы массива могут быть обработаны, прежде чем метод вернёт результат ненормальным способом. Какие элементы это будут (если таковые имеются), зависит от реализации.
Обсуждение: Из соображений производительности invalidateAll не является виртуальным методом для отдельного переключателя, а применяется к набору переключателей. Некоторые реализации могут иметь большие фиксированные накладные расходы при обработке одной или нескольких операций аннулирования, но небольшие дополнительные расходы при каждом дополнительном аннулировании. В любом случае, эта операция, скорее всего, будет дорогостоящей, поскольку другим потокам, возможно, придётся каким-то образом прервать их, чтобы заставить их заметить обновлённое состояние переключателя. Однако можно заметить, что один вызов для аннулирования нескольких переключателей имеет тот же формальный эффект, что и множество вызовов, каждый для только одного из переключателей.
Примечание об реализации: Простые реализации SwitchPoint могут использовать частный MutableCallSite для публикации состояния переключателя. В такой реализации метод invalidateAll может просто изменить целевой объект вызова и выпустить один вызов для синхронизации всех частных вызовов синхронизации.
- Параметры:
-
switchPoints- массив вызовов, которые нужно синхронизировать - Исключения:
-
NullPointerException- если ссылка на массивswitchPointsравна null или массив содержит null
© 1993, 2021, 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/17/docs/api/java.base/java/lang/invoke/SwitchPoint.html