/* * Copyright (c) 2016. Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.amazonaws.util; /** * Manages capacity of a finite resource. Capacity can be acquired and * released. */ public class CapacityManager { private volatile int availableCapacity; private final int maxCapacity; private final Object lock = new Object(); /** * Creates a CapacityManager. * * @param maxCapacity maximum capacity of this resource. * available capacity will initially be set to this value. * if a negative value is provided the capacity manager will operate in a no-op * passthrough mode in which all acquire calls will return true. */ public CapacityManager(final int maxCapacity) { this.maxCapacity = maxCapacity; this.availableCapacity = maxCapacity; } /** * Attempts to acquire a single capacity unit. * If acquired, capacity will be consumed from the available pool. * @return true if capacity can be acquired, false if not */ public boolean acquire() { return acquire(1); } /** * Attempts to acquire a given amount of capacity. * If acquired, capacity will be consumed from the available pool. * * @param capacity capacity to acquire * @return true if capacity can be acquired, false if not * @throws IllegalArgumentException if given capacity is negative */ public boolean acquire(int capacity) { if (capacity < 0) { throw new IllegalArgumentException("capacity to acquire cannot be negative"); } if (availableCapacity < 0) { return true; } synchronized (lock) { if (availableCapacity - capacity >= 0) { availableCapacity -= capacity; return true; } else { return false; } } } /** * Releases a single unit of capacity back to the pool, making it available * to consumers. */ public void release() { release(1); } /** * Releases a given amount of capacity back to the pool, making it available * to consumers. * * @param capacity capacity to release * @throws IllegalArgumentException if given capacity is negative */ public void release(int capacity) { if (capacity < 0) { throw new IllegalArgumentException("capacity to release cannot be negative"); } // in the common 'good' case where we have our full capacity available we can // short circuit going any further and avoid unnecessary locking. if (availableCapacity >= 0 && availableCapacity != maxCapacity) { synchronized (lock) { availableCapacity = Math.min((availableCapacity + capacity), maxCapacity); } } } /** * Returns the currently consumed capacity. * * @return consumed capacity */ public int consumedCapacity() { return (availableCapacity < 0) ? 0 : (maxCapacity - availableCapacity); } /** * Returns the currently available capacity. * * @return available capacity */ public int availableCapacity() { return availableCapacity; } }