3434import java .util .concurrent .*;
3535import java .util .concurrent .locks .LockSupport ;
3636import java .util .function .Consumer ;
37+ import java .util .function .Supplier ;
3738
3839/**
3940 * <strong>INTERNAL API - This class is subject to change.</strong>
@@ -100,7 +101,12 @@ private FutureImpl(Executor executor, Option<Try<T>> value, Queue<Consumer<Try<T
100101 this .actions = actions ;
101102 this .waiters = waiters ;
102103 try {
103- computation .execute (this ::tryComplete , this ::updateThread );
104+ computation .execute (this ::tryComplete , this ::updateThread , () -> {
105+ // Synchronize as the future could be in the process of cancelling
106+ synchronized (lock ) {
107+ return isCompleted ();
108+ }
109+ });
104110 } catch (Throwable x ) {
105111 tryComplete (Try .failure (x ));
106112 }
@@ -115,7 +121,7 @@ private FutureImpl(Executor executor, Option<Try<T>> value, Queue<Consumer<Try<T
115121 * @return a new {@code FutureImpl} instance
116122 */
117123 static <T > FutureImpl <T > of (Executor executor ) {
118- return new FutureImpl <>(executor , Option .none (), Queue .empty (), Queue .empty (), (complete , updateThread ) -> {});
124+ return new FutureImpl <>(executor , Option .none (), Queue .empty (), Queue .empty (), (complete , updateThread , isCompleted ) -> {});
119125 }
120126
121127 /**
@@ -127,7 +133,7 @@ static <T> FutureImpl<T> of(Executor executor) {
127133 * @return a new {@code FutureImpl} instance
128134 */
129135 static <T > FutureImpl <T > of (Executor executor , Try <? extends T > value ) {
130- return new FutureImpl <>(executor , Option .some (Try .narrow (value )), null , null , (complete , updateThread ) -> {});
136+ return new FutureImpl <>(executor , Option .some (Try .narrow (value )), null , null , (complete , updateThread , isCompleted ) -> {});
131137 }
132138
133139 /**
@@ -140,7 +146,7 @@ static <T> FutureImpl<T> of(Executor executor, Try<? extends T> value) {
140146 * @return a new {@code FutureImpl} instance
141147 */
142148 static <T > FutureImpl <T > sync (Executor executor , Task <? extends T > task ) {
143- return new FutureImpl <>(executor , Option .none (), Queue .empty (), Queue .empty (), (complete , updateThread ) ->
149+ return new FutureImpl <>(executor , Option .none (), Queue .empty (), Queue .empty (), (complete , updateThread , isCompleted ) ->
144150 task .run (complete ::with )
145151 );
146152 }
@@ -156,8 +162,12 @@ static <T> FutureImpl<T> sync(Executor executor, Task<? extends T> task) {
156162 */
157163 static <T > FutureImpl <T > async (Executor executor , Task <? extends T > task ) {
158164 // In a single-threaded context this Future may already have been completed during initialization.
159- return new FutureImpl <>(executor , Option .none (), Queue .empty (), Queue .empty (), (complete , updateThread ) ->
165+ return new FutureImpl <>(executor , Option .none (), Queue .empty (), Queue .empty (), (complete , updateThread , isCompleted ) ->
160166 executor .execute (() -> {
167+ // Avoid performing work, if future is already complete (normally by cancellation)
168+ if (isCompleted .get ()) {
169+ return ;
170+ }
161171 updateThread .run ();
162172 try {
163173 task .run (complete ::with );
@@ -414,6 +424,6 @@ private void handleUncaughtException(Throwable x) {
414424 }
415425
416426 private interface Computation <T > {
417- void execute (Task .Complete <T > complete , Runnable updateThread ) throws Throwable ;
427+ void execute (Task .Complete <T > complete , Runnable updateThread , Supplier < Boolean > isCompleted ) throws Throwable ;
418428 }
419429}
0 commit comments