@@ -356,7 +356,13 @@ public void run() {
356
356
}
357
357
Object valueToSet = getFutureValue (future );
358
358
if (ATOMIC_HELPER .casValue (owner , this , valueToSet )) {
359
- complete (owner );
359
+ complete (
360
+ owner ,
361
+ /*
362
+ * Interruption doesn't propagate through a SetFuture chain (see getFutureValue), so
363
+ * don't invoke interruptTask.
364
+ */
365
+ false );
360
366
}
361
367
}
362
368
}
@@ -656,12 +662,7 @@ mayInterruptIfRunning, new CancellationException("Future.cancel() was called."))
656
662
while (true ) {
657
663
if (ATOMIC_HELPER .casValue (abstractFuture , localValue , valueToSet )) {
658
664
rValue = true ;
659
- // We call interruptTask before calling complete(), which is consistent with
660
- // FutureTask
661
- if (mayInterruptIfRunning ) {
662
- abstractFuture .interruptTask ();
663
- }
664
- complete (abstractFuture );
665
+ complete (abstractFuture , mayInterruptIfRunning );
665
666
if (localValue instanceof SetFuture ) {
666
667
// propagate cancellation to the future set in setfuture, this is racy, and we don't
667
668
// care if we are successful or not.
@@ -779,7 +780,7 @@ public void addListener(Runnable listener, Executor executor) {
779
780
protected boolean set (@ ParametricNullness V value ) {
780
781
Object valueToSet = value == null ? NULL : value ;
781
782
if (ATOMIC_HELPER .casValue (this , null , valueToSet )) {
782
- complete (this );
783
+ complete (this , /*callInterruptTask=*/ false );
783
784
return true ;
784
785
}
785
786
return false ;
@@ -804,7 +805,7 @@ protected boolean set(@ParametricNullness V value) {
804
805
protected boolean setException (Throwable throwable ) {
805
806
Object valueToSet = new Failure (checkNotNull (throwable ));
806
807
if (ATOMIC_HELPER .casValue (this , null , valueToSet )) {
807
- complete (this );
808
+ complete (this , /*callInterruptTask=*/ false );
808
809
return true ;
809
810
}
810
811
return false ;
@@ -847,7 +848,13 @@ protected boolean setFuture(ListenableFuture<? extends V> future) {
847
848
if (future .isDone ()) {
848
849
Object value = getFutureValue (future );
849
850
if (ATOMIC_HELPER .casValue (this , null , value )) {
850
- complete (this );
851
+ complete (
852
+ this ,
853
+ /*
854
+ * Interruption doesn't propagate through a SetFuture chain (see getFutureValue), so
855
+ * don't invoke interruptTask.
856
+ */
857
+ false );
851
858
return true ;
852
859
}
853
860
return false ;
@@ -989,14 +996,26 @@ private static Object getFutureValue(ListenableFuture<?> future) {
989
996
}
990
997
991
998
/** Unblocks all threads and runs all listeners. */
992
- private static void complete (AbstractFuture <?> param ) {
999
+ private static void complete (AbstractFuture <?> param , boolean callInterruptTask ) {
993
1000
// Declare a "true" local variable so that the Checker Framework will infer nullness.
994
1001
AbstractFuture <?> future = param ;
995
1002
996
1003
Listener next = null ;
997
1004
outer :
998
1005
while (true ) {
999
1006
future .releaseWaiters ();
1007
+ /*
1008
+ * We call interruptTask() immediately before afterDone() so that migrating between the two
1009
+ * can be a no-op.
1010
+ */
1011
+ if (callInterruptTask ) {
1012
+ future .interruptTask ();
1013
+ /*
1014
+ * Interruption doesn't propagate through a SetFuture chain (see getFutureValue), so don't
1015
+ * invoke interruptTask on any subsequent futures.
1016
+ */
1017
+ callInterruptTask = false ;
1018
+ }
1000
1019
// We call this before the listeners in order to avoid needing to manage a separate stack data
1001
1020
// structure for them. Also, some implementations rely on this running prior to listeners
1002
1021
// so that the cleanup work is visible to listeners.
0 commit comments