@Override protected boolean consumeOrAwaitImpl(long tokensToConsume, long waitIfBusyTimeLimit) throws InterruptedException { Bandwidth[] bandwidths = configuration.getBandwidths(); boolean isWaitingLimited = waitIfBusyTimeLimit > 0; final long methodStartTime = configuration.getTimeMeter().currentTime(); long currentTime = methodStartTime; long methodDuration = 0; boolean isFirstCycle = true; BucketState previousState = stateReference.get(); BucketState newState = previousState.clone(); while (true) { if (isFirstCycle) { isFirstCycle = false; } else { currentTime = configuration.getTimeMeter().currentTime(); methodDuration = currentTime - methodStartTime; if (isWaitingLimited && methodDuration >= waitIfBusyTimeLimit) { return false; } previousState = stateReference.get(); newState.copyState(previousState); } newState.refill(bandwidths, currentTime); long timeToCloseDeficit = newState.delayAfterWillBePossibleToConsume(bandwidths, currentTime, tokensToConsume); if (timeToCloseDeficit == Long.MAX_VALUE) { return false; } if (timeToCloseDeficit == 0) { newState.consume(bandwidths, tokensToConsume); if (stateReference.compareAndSet(previousState, newState)) { return true; } else { continue; } } if (isWaitingLimited) { long sleepingTimeLimit = waitIfBusyTimeLimit - methodDuration; if (timeToCloseDeficit >= sleepingTimeLimit) { return false; } } configuration.getTimeMeter().sleep(timeToCloseDeficit); } }
@Override protected boolean tryConsumeImpl(long tokensToConsume) { BucketState previousState = stateReference.get(); BucketState newState = previousState.clone(); Bandwidth[] bandwidths = configuration.getBandwidths(); long currentTime = configuration.getTimeMeter().currentTime(); while (true) { newState.refill(bandwidths, currentTime); long availableToConsume = newState.getAvailableTokens(bandwidths); if (tokensToConsume > availableToConsume) { return false; } newState.consume(bandwidths, tokensToConsume); if (stateReference.compareAndSet(previousState, newState)) { return true; } else { previousState = stateReference.get(); newState.copyState(previousState); } } }
@Override protected long consumeAsMuchAsPossibleImpl(long limit) { BucketState previousState = stateReference.get(); BucketState newState = previousState.clone(); Bandwidth[] bandwidths = configuration.getBandwidths(); long currentTime = configuration.getTimeMeter().currentTime(); while (true) { newState.refill(bandwidths, currentTime); long availableToConsume = newState.getAvailableTokens(bandwidths); long toConsume = Math.min(limit, availableToConsume); if (toConsume == 0) { return 0; } newState.consume(bandwidths, toConsume); if (stateReference.compareAndSet(previousState, newState)) { return toConsume; } else { previousState = stateReference.get(); newState.copyState(previousState); } } }
public LockFreeBucket(BucketConfiguration configuration) { super(configuration); this.configuration = configuration; BucketState initialState = BucketState.createInitialState(configuration); this.stateReference = new AtomicReference<>(initialState); }