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

com.ajjpj.afoundation.collection.mutable.ARingBuffer Maven / Gradle / Ivy

There is a newer version: 1.0-pre19
Show newest version
package com.ajjpj.afoundation.collection.mutable;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Iterator;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;


/**
 * This is a fixed-size data structure that is optimized for write performance with concurrent reads. Once
 *  the buffer is full, the least recent elements are overwritten.

* * Implementation note: This class uses synchronized instead of ReentrantLock or ReentrantReadWriteLock. The reason * is that read access - even from several threads concurrently - leads to little lock contention, while single threaded write access can significantly * profit from biased locking. A performance test with one writer thread and ten reader threads ran an order of magnitude faster with synchronized. * * @author arno */ public class ARingBuffer implements Iterable { /** * This is the number of bins allocated in addition to the nominal buffer size to allow room for buffering write * lag when reading. */ private final Class elementClass; private final int bufSize; private final T[] buffer; private final ReadWriteLock lock = new ReentrantReadWriteLock(); /** * points to the offset with the first (oldest) element, which is also the next one to be overwritten */ private int next = 0; private boolean isFull = false; public ARingBuffer(Class cls, int maxSize) { elementClass = cls; bufSize = maxSize; buffer = allocate(); } public void put(T o) { synchronized(this) { buffer[next] = o; next = asBufIndex(next+1); if(next == 0) { isFull = true; } } } public void clear() { synchronized(this) { next = 0; isFull = false; Arrays.fill(buffer, null); } } @SuppressWarnings("unchecked") private T[] allocate() { return (T[]) Array.newInstance(elementClass, bufSize); } private int asBufIndex(int rawIdx) { return (rawIdx + bufSize) % bufSize; } /** * Iterators returned via this method are stable with regard to changes, i.e. changes may occur during iteration, * but they do not affect the elements returned by the iterator. */ @Override public Iterator iterator() { synchronized(this) { return new Iterator() { final T[] snapshot = allocate(); final int end = next; int curPos; boolean hasNext; { System.arraycopy(buffer, 0, snapshot, 0, bufSize); curPos = isFull ? next : 0; hasNext = isFull || end != 0; } @Override public boolean hasNext() { return hasNext; } @Override public T next() { if(! hasNext) { throw new IndexOutOfBoundsException(); } final T result = snapshot[curPos]; curPos = asBufIndex(curPos + 1); hasNext = curPos != end; return result; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy