fix(commons): synchronize in ScopedValue.Carrier since child threads may access values from parent threads
ci/woodpecker/push/woodpecker Pipeline was successful Details

This commit is contained in:
Johannes Frohnmeyer 2024-05-05 13:00:58 +02:00
parent 4b0d67b702
commit ae263e15ea
Signed by: Johannes
GPG Key ID: E76429612C2929F4
1 changed files with 26 additions and 11 deletions

View File

@ -3,6 +3,7 @@ package io.gitlab.jfronny.commons.concurrent;
import java.util.Deque;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
@ -75,8 +76,8 @@ public class ScopedValue<T> {
}
private static class Carrier<T> {
private Deque<T> value;
private Carrier<T> parent;
private final Deque<T> value;
private final Carrier<T> parent;
public Carrier() {
this(null);
@ -87,10 +88,18 @@ public class ScopedValue<T> {
this.parent = parent;
}
private Optional<T> valueIfPresent() {
synchronized (value) {
if (!value.isEmpty()) return Optional.of(value.peek());
return Optional.empty();
}
}
public T getValue() {
if (!value.isEmpty()) return value.peek();
if (parent == null) throw new NoSuchElementException("No value present");
return parent.getValue();
return valueIfPresent().orElseGet(() -> {
if (parent == null) throw new NoSuchElementException("No value present");
return parent.getValue();
});
}
public boolean isPresent() {
@ -100,21 +109,27 @@ public class ScopedValue<T> {
}
public void setValue(T value) {
this.value.push(value);
synchronized (this.value) {
this.value.push(value);
}
}
public void clear() {
value.pop();
synchronized (this.value) {
value.pop();
}
}
public T orElse(T other) {
if (!value.isEmpty()) return value.peek();
if (parent == null) return other;
return parent.orElse(other);
return valueIfPresent().orElseGet(() -> {
if (parent == null) return other;
return parent.orElse(other);
});
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (!value.isEmpty()) return value.peek();
Optional<T> v = valueIfPresent();
if (v.isPresent()) return v.get();
if (parent == null) throw exceptionSupplier.get();
return parent.orElseThrow(exceptionSupplier);
}