#java #java-8
#java #java-8
Вопрос:
Почему FutureTask больше не использует AQS внутренне в jdk8 в отличие от jdk7?
В комментариях к jdk 8 сказано, что это сделано: «избегайте удивлять пользователей сохранением статуса прерывания во время * гонки отмены».
Я хотел бы узнать больше об этом варианте использования, и если есть пример нежелательного поведения, это изменение исправляет.
Комментарии:
1. В комментарии говорится » / * * Примечания к пересмотру: Это отличается от предыдущих версий этого * класса, которые полагались на AbstractQueuedSynchronizer, главным образом для того, чтобы * не удивлять пользователей сохранением статуса прерывания во время * гонок отмены. Управление синхронизацией в текущем проекте зависит * от поля «состояние», обновляемого через CAS для отслеживания завершения, наряду * с простым стеком Treiber для хранения ожидающих потоков. */»
2. Конечно, имеет, я просто хотел получить еще несколько объяснений
3. Если у вас есть конкретный вопрос или конкретная точка, которую вы хотите объяснить, пожалуйста, обновите свой вопрос.
4. Я просто хотел бы увидеть пример того, почему решение jdk 7 было недостаточным. Обновил вопрос.
Ответ №1:
Рассмотрим следующий сценарий:
- Поток A находится внутри
run()
методаFutureTask
- Вызывается поток B
cancel(true)
, который успешно переключает состояние сRUNNING
наCANCELLED
(до Java 8) - Поток A завершает
run()
метод - Поток B, все еще находящийся внутри
cancel(true)
, прерывает поток - Поток A, теперь находящийся вне
FutureTask
, получает ложное прерывание
Новый дизайн исправляет это, вводя разные состояния для INTERRUPTING
, устанавливаемые перед попыткой прерывания потока, и INTERRUPTED
, устанавливаемые после. Затем по завершении вызывается следующий метод:
/**
* Ensures that any interrupt from a possible cancel(true) is only
* delivered to a task while in run or runAndReset.
*/
private void handlePossibleCancellationInterrupt(int s) {
// It is possible for our interrupter to stall before getting a
// chance to interrupt us. Let's spin-wait patiently.
if (s == INTERRUPTING)
while (state == INTERRUPTING)
Thread.yield(); // wait out pending interrupt
…
Обратите внимание, что это все еще не сбрасывает прерванное состояние потока. Это по-прежнему является обязанностью вызывающей стороны, например, ExecutorService
реализации. Но теперь, когда гарантировано, что в случае отмены было выполнено потенциальное прерывание при возврате из run()
метода, легко сбросить флаг. Без этой гарантии, в случае резкой отмены, было бы возможно, что прерывание произойдет после попытки сбросить прерванное состояние.