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.10.0
Show newest version
package pl.allegro.tech.hermes.consumers.consumer.rate;

import javax.annotation.concurrent.ThreadSafe;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/*
 *  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.
     *
     * @param newMax
     */
    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