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

com.conversantmedia.util.concurrent.ConcurrentStack Maven / Gradle / Ivy

There is a newer version: 1.2.21
Show newest version
package com.conversantmedia.util.concurrent;

/*
 * #%L
 * Conversant Disruptor
 * ~~
 * Conversantmedia.com © 2016, Conversant, Inc. Conversant® is a trademark of Conversant, Inc.
 * ~~
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License 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.
 * #L%
 */

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReferenceArray;

/**
 * Concurrent "lock-free" version of a stack.
 *
 * @author John Cairns
 * 

Date: 7/9/12

*/ public class ConcurrentStack implements BlockingStack { private final int size; private final AtomicReferenceArray stack; // representing the top of the stack private final AtomicInteger stackTop = new PaddedAtomicInteger(0); private final SequenceLock seqLock = new SequenceLock(); private final Condition stackNotFullCondition; private final Condition stackNotEmptyCondition; public ConcurrentStack(final int size) { this(size, SpinPolicy.WAITING); } /** * construct a new stack of given capacity * * @param size - the stack size * @param spinPolicy - determine the level of cpu aggressiveness in waiting */ public ConcurrentStack(final int size, final SpinPolicy spinPolicy) { int stackSize = 1; while(stackSize < size) stackSize <<=1; this.size = stackSize; stack = new AtomicReferenceArray(stackSize); switch(spinPolicy) { case BLOCKING: stackNotFullCondition = new StackNotFull(); stackNotEmptyCondition = new StackNotEmpty(); break; case SPINNING: stackNotFullCondition = new SpinningStackNotFull(); stackNotEmptyCondition = new SpinningStackNotEmpty(); break; case WAITING: default: stackNotFullCondition = new WaitingStackNotFull(); stackNotEmptyCondition = new WaitingStackNotEmpty(); } } @Override public boolean push(final N n, final long time, final TimeUnit unit) throws InterruptedException { final long endDate = System.nanoTime() + unit.toNanos(time); while(!push(n)) { if(endDate - System.nanoTime() < 0) { return false; } Condition.waitStatus(time, unit, stackNotFullCondition); } stackNotEmptyCondition.signal(); return true; } @Override public void pushInterruptibly(final N n) throws InterruptedException { while(!push(n)) { if(Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } stackNotFullCondition.await(); } stackNotEmptyCondition.signal(); } @Override public boolean contains(final N n) { if(n != null) { for(int i = 0; i0L) { try { final int stackTop = this.stackTop.get(); if(size>stackTop) { try { stack.set(stackTop, n); stackNotEmptyCondition.signal(); return true; } finally { this.stackTop.lazySet(stackTop+1); } } else { return false; } } finally { seqLock.unlock(writeLock); } } spin = Condition.progressiveYield(spin); } } /** * peek at the top of the stack * * @return N - the object at the top of the stack */ @Override public N peek() { // read the current cursor int spin = 0; for(;;) { final long readLock = seqLock.readLock(); final int stackTop = this.stackTop.get(); final N n = stack.get(stackTop-1); if(seqLock.readLockHeld(readLock)) { if(stackTop>0) { return stack.get(stackTop-1); } else { return null; } } spin = Condition.progressiveYield(spin); } } /** * pop the next element off the stack * @return N - The object on the top of the stack */ @Override public N pop() { int spin = 0; // now pop the stack for(;;) { final long writeLock = seqLock.tryWriteLock(); if(writeLock > 0) { try { final int stackTop = this.stackTop.get(); final int lastRef = stackTop-1; if(stackTop>0) { try { // if we can modify the stack - i.e. nobody else is modifying final N n = stack.get(lastRef); stack.set(lastRef, null); stackNotFullCondition.signal(); return n; } finally { this.stackTop.lazySet(lastRef); } } else { return null; } } finally { seqLock.unlock(writeLock); } } spin = Condition.progressiveYield(spin); } } @Override public N pop(final long time, final TimeUnit unit) throws InterruptedException { final long endTime = System.nanoTime() + unit.toNanos(time); for(;;) { final N n = pop(); if(n != null) { stackNotFullCondition.signal(); return n; } else { if(endTime - System.nanoTime() < 0) { return null; } } Condition.waitStatus(time, unit, stackNotEmptyCondition); } } @Override public N popInterruptibly() throws InterruptedException { for(;;) { final N n = pop(); if(n != null) { stackNotFullCondition.signal(); return n; } else { if(Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } } stackNotEmptyCondition.await(); } } /** * Return the size of the stack * @return int - number of elements in the stack */ @Override public int size() { return stackTop.get(); } /** * how much available space in the stack */ @Override public int remainingCapacity() { return size - stackTop.get(); } /** * @return boolean - true if stack is currently empty */ @Override public boolean isEmpty() { return stackTop.get()==0; } /** * clear the stack - does not null old references */ @Override public void clear() { int spin = 0; for(;;) { final long writeLock = seqLock.tryWriteLock(); if(writeLock > 0L) { final int stackTop = this.stackTop.get(); if(stackTop>0) { try { for(int i = 0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy