Класс ClassValue<T>
- java.lang.Object
-
- java.lang.ClassValue<T>
public abstract class ClassValue<T> extends Object
Лениво ассоциирует вычисленный результат с (потенциально) каждым типом. Например, если динамическому языку необходимо построить таблицу диспетчеризации сообщений для каждого класса, встреченного в месте отправки сообщения, он может использовать ClassValue для кэширования информации, необходимой для быстрого отправки сообщения для каждого встреченного класса.
- Since:
- 1.7
Конструкторы
| Модификатор | Конструктор и описание |
|---|---|
protected |
ClassValue() Единственный конструктор. |
Методы
| Модификатор и тип | Метод и описание |
|---|---|
protected abstract T |
computeValue(Class<?> type) Вычисляет производное значение данного класса для данного |
T |
get(Class<?> type) Возвращает значение для данного класса. |
void |
remove(Class<?> type) Удаляет ассоциированное значение для данного класса. |
Методы, унаследованные от класса java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
Конструкторы
ClassValue
protected ClassValue()
Единственный конструктор. (Для вызова конструкторами подклассов, обычно неявно).
Методы
computeValue
protected abstract T computeValue(Class<?> type)
Вычисляет производное значение данного класса для этого ClassValue.
Этот метод будет вызван в первом потоке, который получит доступ к значению с помощью метода get.
Обычно этот метод вызывается не более одного раза на класс, но он может быть вызван снова, если был сделан вызов remove.
Если этот метод генерирует исключение, соответствующий вызов get завершится с этим исключением, и никакое значение класса не будет записано.
- Параметры:
-
type- тип, значение класса которого должно быть вычислено - Возвращает:
- нововычисленное значение, связанное с этим
ClassValue, для данного класса или интерфейса - См. также:
-
get(java.lang.Class<?>),remove(java.lang.Class<?>)
get
public T get(Class<?> type)
Возвращает значение для данного класса. Если значение ещё не было вычислено, оно получается путём вызова метода computeValue.
Фактическая установка значения на класс выполняется атомарно. В этот момент, если несколько конкурирующих потоков вычислили значения, выбирается одно, и возвращается всем конкурирующим потокам.
Параметр type обычно является классом, но он может быть любого типа, например, интерфейсом, примитивным типом (например, int.class) или void.class.
В отсутствие вызовов remove, значение класса имеет простую диаграмму состояния: неинициализирован и инициализирован. Когда производятся вызовы remove, правила наблюдения за значением становятся более сложными. См. документацию для remove для получения дополнительной информации.
- Параметры:
-
type- тип, значение класса которого должно быть вычислено или извлечено - Возвращает:
- текущее значение, связанное с этим
ClassValue, для данного класса или интерфейса - Исключения:
-
NullPointerException- если аргумент равен null - См. также:
-
remove(java.lang.Class<?>),computeValue(java.lang.Class<?>)
remove
public void remove(Class<?> type)
Удаляет ассоциированное значение для данного класса. Если это значение впоследствии считывается для того же класса, его значение будет повторно инициализировано вызовом метода computeValue. Это может привести к дополнительному вызову метода computeValue для данного класса.
Для объяснения взаимодействия между вызовами get и remove необходимо смоделировать переходы состояния значения класса, учитывая чередование между неинициализированным и инициализированным состояниями. Для этого пронумеруйте эти состояния последовательно, и обратите внимание, что неинициализированные (или удалённые) состояния имеют чётные номера, а инициализированные (или повторно инициализированные) состояния имеют нечётные номера.
Когда поток T удаляет значение класса в состоянии 2N, ничего не происходит, так как значение класса уже неинициализировано. В противном случае состояние атомарно переходит в 2N+1.
Когда поток T запрашивает значение класса в состоянии 2N, поток сначала пытается инициализировать значение класса в состояние 2N+1 путём вызова computeValue и установки результирующего значения.
Когда T пытается установить новое вычисленное значение, если состояние всё ещё находится в 2N, значение класса будет инициализировано вычисленным значением, переведя его в состояние 2N+1.
В противном случае, независимо от того, является ли новое состояние чётным или нечётным, T отбросит нововычисленное значение и повторит операцию get.
Отбрасывание и повторная попытка являются важным условием, поскольку в противном случае T мог бы потенциально установить катастрофически устаревшее значение. Например:
-
TвызываетCV.get(C)и видит состояние2N -
Tбыстро вычисляет зависящее от времени значениеV0и готовится установить его -
Tсталкивается с неудачным страничным или планировочным событием и засыпает на долгое время - ...между тем,
T2также вызываетCV.get(C)и видит состояние2N -
T2быстро вычисляет аналогичное зависящее от времени значениеV1и устанавливает его наCV.get(C) -
T2(или третий поток) затем вызываетCV.remove(C), отменяя работуT2 - предыдущие действия
T2повторяются несколько раз - также, соответствующие вычисленные значения меняются со временем:
V1,V2, ... - ...между тем,
Tпросыпается и пытается установитьV0; это должно завершиться неудачей
CV.computeValue использует блокировки для правильного наблюдения за зависящими от времени состояниями при вычислении V1 и т. д. Это не устраняет угрозу устаревшего значения, поскольку существует временной интервал между возвратом computeValue в T и установкой нового значения. Никакая пользовательская синхронизация невозможна в течение этого времени.- Параметры:
-
type- тип, значение класса которого должно быть удалено - Исключения:
-
NullPointerException- если аргумент равен 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.