package phantomlancer.ringbuffer;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RingBuffer<E> {
private static final Logger LOG = LoggerFactory.getLogger(RingBuffer.class);
private Object[] RING;
private int size;
private int mask;
private long blocktime;
private AtomicReference<Integer> WP;
private AtomicReference<Integer> RP;
public RingBuffer(int size, long blocktime) {
RING = new Object[size];
Validate.isTrue(size > 2 && Integer.bitCount(size) == 1, "Size must be a power of 2 and greater than 2");
this.size = size;
this.mask = size - 1;
this.blocktime = blocktime;
WP = new AtomicReference<Integer>(0);
RP = new AtomicReference<Integer>(0);
}
public RingBuffer(int size) {
this(size, 10);
}
private boolean checkFull(Integer w) {
return mod(w) == RP.get();
}
private boolean checkEmpty(Integer r) {
return WP.get().equals(r);
}
public int curSize() {
return (WP.get() + size - RP.get()) % size;
}
public void add(E e, int mode) {
for (;;) {
Integer cur = WP.get();
if (checkFull(cur)) {
if (mode == Mode.MODE_SKIP) {
return;
}
if (mode == Mode.MODE_BLOCKING) {
block();
}
} else {
if (WP.compareAndSet(cur, mod(cur))) {
// while (RING[cur] != null) {//没有可能进入
// Thread.yield();
// }
RING[cur] = e;
return;
}
}
}
}
@SuppressWarnings("unchecked")
public E get(int mode) {
for (;;) {
Integer cur = RP.get();
if (checkEmpty(cur)) {
if (mode == Mode.MODE_SKIP) {
return null;
}
if (mode == Mode.MODE_BLOCKING) {
block();
return get(Mode.MODE_SKIP);
}
} else {
Object o = RING[cur];
if (RP.compareAndSet(cur, mod(cur))) {
while (o == null) {
Thread.yield();
o = RING[cur];
}
RING[cur] = null;
return (E) o;
}
}
}
}
public List<E> get(int mode, int size, long timeout) {
List<E> result = new LinkedList<E>();
long t1 = System.currentTimeMillis();
for (int i = 0; i < size; i++) {
E e = get(mode);
if (e != null) {
result.add(e);
}
if (timeout > 0 && timeout < System.currentTimeMillis() - t1) {
break;
}
}
return result;
}
public int size() {
return size;
}
private int mod(int i) {
return (i + 1) & mask;
}
private void block() {
try {
Thread.sleep(blocktime);
} catch (InterruptedException e) {
LOG.error("RingBuffer Block:", e);
}
}
public interface Mode {
public static final int MODE_SKIP = 0;
public static final int MODE_BLOCKING = 1;
}
}