Почему FutureTask больше не использует AQS внутренне?

#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() метода, легко сбросить флаг. Без этой гарантии, в случае резкой отмены, было бы возможно, что прерывание произойдет после попытки сбросить прерванное состояние.