pl.allegro.tech.hermes.consumers.consumer.rate.AdjustableSemaphore Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hermes-consumers Show documentation
Show all versions of hermes-consumers Show documentation
Fast and reliable message broker built on top of Kafka.
package pl.allegro.tech.hermes.consumers.consumer.rate;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import javax.annotation.concurrent.ThreadSafe;
/*
* CAUTION!
*
* This is repackaged version of com.genius.concurrency.AdjustableSemaphore with few changes.
* http://blog.teamlazerbeez.com/2009/04/20/javas-semaphore-resizing/
*
* Most notable changes:
* - set maxPermits in constructor
*
* Implementation was deliberately not refactored for easier comparison with the original.
*
* */
/**
* A simple implementation of an adjustable semaphore.
*/
@ThreadSafe
public final class AdjustableSemaphore {
/**
* Semaphore starts at 0 capacity; must be set by setMaxPermits before use.
*/
private final ResizeableSemaphore semaphore;
/**
* How many permits are allowed as governed by this semaphore.
* Access must be synchronized on this object.
*/
private int maxPermits = 0;
/**
* New instances should be configured with setMaxPermits().
*/
public AdjustableSemaphore(int maxPermits) {
this.maxPermits = maxPermits;
this.semaphore = new ResizeableSemaphore(maxPermits);
}
/*
* Must be synchronized because the underlying int is not thread safe
*/
/**
* Set the max number of permits. Must be greater than zero.
*
* Note that if there are more than the new max number of permits currently
* outstanding, any currently blocking threads or any new threads that start
* to block after the call will wait until enough permits have been released to
* have the number of outstanding permits fall below the new maximum. In
* other words, it does what you probably think it should.
*/
public synchronized void setMaxPermits(int newMax) {
if (newMax < 1) {
throw new IllegalArgumentException("Semaphore size must be at least 1,"
+ " was " + newMax);
}
int delta = newMax - this.maxPermits;
if (delta == 0) {
return;
} else if (delta > 0) {
// new max is higher, so release that many permits
this.semaphore.release(delta);
} else {
delta *= -1;
// delta < 0.
// reducePermits needs a positive #, though.
this.semaphore.reducePermits(delta);
}
this.maxPermits = newMax;
}
/**
* Release a permit back to the semaphore. Make sure not to double-release.
*/
public void release() {
this.semaphore.release();
}
/**
* Get a permit, blocking if necessary.
*
* @throws InterruptedException if interrupted while waiting for a permit
*/
public void acquire() throws InterruptedException {
this.semaphore.acquire();
}
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException {
return this.semaphore.tryAcquire(timeout, unit);
}
public int availablePermits() {
return this.semaphore.availablePermits();
}
/**
* A trivial subclass of Semaphore
that exposes the reducePermits
* call to the parent class. Doug Lea says it's ok...
* http://osdir.com/ml/java.jsr.166-concurrency/2003-10/msg00042.html
*/
private static final class ResizeableSemaphore extends Semaphore {
private static final long serialVersionUID = 1L;
/**
* Create a new semaphore with 0 permits.
*/
ResizeableSemaphore(int maxPermits) {
super(maxPermits);
}
@Override
protected void reducePermits(int reduction) {
super.reducePermits(reduction);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy