Skip to content

Commit d5a86e4

Browse files
Koziolekpivovarit
authored andcommitted
Replace synchronization by Lock in FutureImpl (#2912)
I replaced _synchronized_ blocks with Lock for the sake of Virtual Threads support. More details: https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html#GUID-04C03FFC-066D-4857-85B9-E5A27A875AF9 ---- Similar to #2845
1 parent 100554b commit d5a86e4

File tree

1 file changed

+28
-7
lines changed

1 file changed

+28
-7
lines changed

vavr/src/main/java/io/vavr/concurrent/FutureImpl.java

+28-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525

2626
import java.util.Objects;
2727
import java.util.concurrent.*;
28+
import java.util.concurrent.locks.Lock;
2829
import java.util.concurrent.locks.LockSupport;
30+
import java.util.concurrent.locks.ReentrantLock;
2931
import java.util.function.Consumer;
3032

3133
/**
@@ -45,7 +47,7 @@ final class FutureImpl<T> implements Future<T> {
4547
/**
4648
* Used to synchronize state changes.
4749
*/
48-
private final Object lock = new Object();
50+
private final Lock lock;
4951

5052
/**
5153
* Indicates if this Future is cancelled
@@ -87,8 +89,10 @@ final class FutureImpl<T> implements Future<T> {
8789

8890
// single constructor
8991
private FutureImpl(Executor executor, Option<Try<T>> value, Queue<Consumer<Try<T>>> actions, Queue<Thread> waiters, Computation<T> computation) {
92+
this.lock = new ReentrantLock();
9093
this.executor = executor;
91-
synchronized (lock) {
94+
lock.lock();
95+
try {
9296
this.cancelled = false;
9397
this.value = value;
9498
this.actions = actions;
@@ -98,6 +102,8 @@ private FutureImpl(Executor executor, Option<Try<T>> value, Queue<Consumer<Try<T
98102
} catch (Throwable x) {
99103
tryComplete(Try.failure(x));
100104
}
105+
} finally {
106+
lock.unlock();
101107
}
102108
}
103109

@@ -219,8 +225,11 @@ private void _await(long start, long timeout, TimeUnit unit) {
219225
public boolean block() {
220226
try {
221227
if (!threadEnqueued) {
222-
synchronized (lock) {
228+
lock.lock();
229+
try {
223230
waiters = waiters.enqueue(waitingThread);
231+
} finally {
232+
lock.unlock();
224233
}
225234
threadEnqueued = true;
226235
}
@@ -256,14 +265,17 @@ public boolean isReleasable() {
256265
@Override
257266
public boolean cancel(boolean mayInterruptIfRunning) {
258267
if (!isCompleted()) {
259-
synchronized (lock) {
268+
lock.lock();
269+
try {
260270
if (!isCompleted()) {
261271
if (mayInterruptIfRunning && this.thread != null) {
262272
this.thread.interrupt();
263273
}
264274
this.cancelled = tryComplete(Try.failure(new CancellationException()));
265275
return this.cancelled;
266276
}
277+
} finally {
278+
lock.unlock();
267279
}
268280
}
269281
return false;
@@ -272,7 +284,8 @@ public boolean cancel(boolean mayInterruptIfRunning) {
272284
private void updateThread() {
273285
// cancellation may have been initiated by a different thread before this.thread is set by the worker thread
274286
if (!isCompleted()) {
275-
synchronized (lock) {
287+
lock.lock();
288+
try {
276289
if (!isCompleted()) {
277290
this.thread = Thread.currentThread();
278291
try {
@@ -281,6 +294,8 @@ private void updateThread() {
281294
// we are not allowed to set the uncaught exception handler of the worker thread ¯\_(ツ)_/¯
282295
}
283296
}
297+
} finally {
298+
lock.unlock();
284299
}
285300
}
286301
}
@@ -322,12 +337,15 @@ public Future<T> onComplete(Consumer<? super Try<T>> action) {
322337
if (isCompleted()) {
323338
perform(action);
324339
} else {
325-
synchronized (lock) {
340+
lock.lock();
341+
try {
326342
if (isCompleted()) {
327343
perform(action);
328344
} else {
329345
actions = actions.enqueue((Consumer<Try<T>>) action);
330346
}
347+
} finally {
348+
lock.unlock();
331349
}
332350
}
333351
return this;
@@ -362,7 +380,8 @@ boolean tryComplete(Try<? extends T> value) {
362380
final Queue<Consumer<Try<T>>> actions;
363381
final Queue<Thread> waiters;
364382
// it is essential to make the completed state public *before* performing the actions
365-
synchronized (lock) {
383+
lock.lock();
384+
try {
366385
if (isCompleted()) {
367386
actions = null;
368387
waiters = null;
@@ -374,6 +393,8 @@ boolean tryComplete(Try<? extends T> value) {
374393
this.waiters = null;
375394
this.thread = null;
376395
}
396+
} finally {
397+
lock.unlock();
377398
}
378399
if (waiters != null) {
379400
waiters.forEach(this::unlock);

0 commit comments

Comments
 (0)