
com.netflix.concurrency.limits.limiter.BlockingLimiter Maven / Gradle / Ivy
package com.netflix.concurrency.limits.limiter;
import com.netflix.concurrency.limits.Limiter;
import java.util.Optional;
/**
* {@link Limiter} that blocks the caller when the limit has been reached. The caller is
* blocked until the limiter has been released. This limiter is commonly used in batch
* clients that use the limiter as a back-pressure mechanism.
*
* @param
*/
public final class BlockingLimiter implements Limiter {
public static BlockingLimiter wrap(Limiter delegate) {
return new BlockingLimiter(delegate);
}
private final Limiter delegate;
/**
* Lock used to block and unblock callers as the limit is reached
*/
private final Object lock = new Object();
private boolean blocked = false;
private BlockingLimiter(Limiter limiter) {
this.delegate = limiter;
}
private Optional tryAcquire(ContextT context) {
synchronized (lock) {
while (true) {
// Try to acquire a token and return immediately if successful
Optional listener;
listener = delegate.acquire(context);
if (listener.isPresent()) {
return listener;
}
// We have reached the limit so block until a token is released
blocked = true;
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return Optional.empty();
}
}
}
}
private void unblock() {
synchronized (lock) {
if (blocked) {
blocked = false;
lock.notify();
}
}
}
@Override
public Optional acquire(ContextT context) {
return tryAcquire(context).map(delegate -> {
return new Listener() {
@Override
public void onSuccess() {
delegate.onSuccess();
unblock();
}
@Override
public void onIgnore() {
delegate.onIgnore();
unblock();
}
@Override
public void onDropped() {
delegate.onDropped();
unblock();
}
};
});
}
@Override
public String toString() {
return "BlockingLimiter [blocked=" + blocked + ", " + delegate + "]";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy