All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.allegro.tech.hermes.consumers.consumer.rate.AdjustableSemaphore Maven / Gradle / Ivy

There is a newer version: 2.8.0
Show newest version
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