import java.util.ArrayList; import java.util.List; /** * * 环形缓冲区<br/> * 一. 写数据:<br/> * 1. push: 当数据已写满时返回false,不然能够正常写入返回true<br/> * 2. pushNoCaseFull: 无论缓冲区是否已写满或当前位置数据是否已读取过,都会写入,不关心读/写指针位置<br/> * 二. 读数据:<br/> * 1. pull: 当缓冲区已读空或还未写入过数据时,返回null<br/> * 另一个重载方法能够对指定位置进行读取,此方法不会影响读指针位置<br/> * 2. pullNoCaseEmpty: 无论当前位置的数据有没有读过,便可以重复读,不关心读/写指针位置,不会影响读指针位置<br/> * 另一个重载方法能够对指定位置进行读取,此方法不会影响读指针位置<br/> * 3. pullBack: 反相读取数据,返回数据状况与pull相同<br/> * 4. pullBackNoCaseEmpty: 反相读取数据,返回数据状况与pullNoCaseEmpty相同<br/> * 三. 是否已写满:<br/> * isFull: 若是写以前关心是否已满,调用此方法<br/> * 四. 是否已读空:<br/> * isEmpty: 读数据以前关心是否已读空,调用此方法<br/> */ public class RingBuffer<T> { private final static byte INVALID = ~0;// 无效数据 private final static byte WRITED = 0;// 数据写过 private final static byte READED = 1;// 数据读过 private int mCapacity = 0; private List<Node> mDataBuf = null; private int mReader = 0; private int mWriter = 0; private class Node { public T object = null; public byte flag = INVALID; public Node(T object, byte flag) { this.object = object; this.flag = flag; } } public RingBuffer(int capacity) { mCapacity = capacity; mDataBuf = new ArrayList<Node>(capacity); } /** * 当数据已写满时返回false,不然能够正常写入返回true<br/> * @param object 被压入的数据 * @return true: 写入成功, false:缓冲区已满 */ public synchronized boolean push(T object) { int size = mDataBuf.size(); if (mWriter < mCapacity) { } else if (mWriter >= mCapacity) {// 写到尾部 mWriter = 0; } if (mCapacity > size) {// 无效数据(未写过数据) Node node = new Node(object, WRITED); mDataBuf.add(mWriter++, node); } else { try { Node oldNode = mDataBuf.get(mWriter); if (null != oldNode && WRITED == oldNode.flag) {// 写已满 return false; } Node node = new Node(object, WRITED); mDataBuf.set(mWriter++, node); } catch (Exception e) { } } return true; } /** * 无论缓冲区是否已写满或当前位置数据是否已读取过,都会写入,不关心读/写指针位置,也不影响读写指针<br/> * @param object 被压入的数据 */ public synchronized void pushNoCaseFull(T object) { int size = mDataBuf.size(); if (mWriter < mCapacity) { } else if (mWriter >= mCapacity) {// 写到尾部 mWriter = 0; } Node node = new Node(object, WRITED); if (mCapacity > size)// 无效数据(未写过数据) mDataBuf.add(mWriter++, node); else mDataBuf.set(mWriter++, node); } /** * 当缓冲区已读空或还未写入过数据时,返回null<br/> * @return 被拉取到的数据, 若是已读空或数据无效返回null */ public synchronized T pull() { if (mReader < mCapacity) { if (mReader < 0) { mReader = 0; } } else if (mReader >= mCapacity) {// 写到尾部 mReader = 0; } try { Node node = mDataBuf.get(mReader); if (null != node && WRITED == node.flag) { node.flag = READED; mDataBuf.set(mReader, node); mReader++; return node.object; } else {// 已读空 } } catch (Exception e) {// No data } return null; } /** * 对指定位置进行读取,此方法不会影响读指针位置<br/> * @return 被拉取到的数据, 若是已读空或数据无效返回null */ public synchronized T pull(int location) { if (location < mCapacity) { if (location < 0) { location = 0; } } else if (location >= mCapacity) {// 写到尾部 location = 0; } try { Node node = mDataBuf.get(location); if (null != node && WRITED == node.flag) { // node.flag = READED; // mDataBuf.set(location, node); return node.object; } else {// 已读空 } } catch (Exception e) {// No data } return null; } /** * 无论当前位置的数据有没有读过,便可以重复读,不关心读/写指针位置,也不影响读写指针<br/> * @return 被拉取到的数据, 若是数据无效返回null */ public synchronized T pullNoCaseEmpty() { if (mReader < mCapacity) { if (mReader < 0) { mReader = 0; } } else if (mReader >= mCapacity) {// 读到尾部 mReader = 0; } try { Node node = mDataBuf.get(mReader); if (null != node && INVALID != node.flag) {// 只要数据有效 // node.flag = READED; // mDataBuf.set(mReader, node); mReader++; return node.object; } else {// 数据无效 } } catch (Exception e) { } return null; } /** * 对指定位置进行读取,此方法不会影响读指针位置<br/> * @return 被拉取到的数据, 若是数据无效返回null */ public synchronized T pullNoCaseEmpty(int location) { if (location < mCapacity) { if (location < 0) { location = 0; } } else if (location >= mCapacity) {// 读到尾部 location = 0; } try { Node node = mDataBuf.get(location); if (null != node && INVALID != node.flag) {// 只要数据有效 // node.flag = READED; // mDataBuf.set(location, node); return node.object; } else {// 数据无效 } } catch (Exception e) { } return null; } /** * 反相读取数据,当缓冲区已读空或还未写入过数据时,返回null<br/> * @return 被拉取到的数据, 若是已读空或数据无效返回null */ public synchronized T pullBack() { if (mReader < mCapacity) { if (mReader < 0) { mReader = mCapacity - 1; } } else if (mReader >= mCapacity) {// 读到尾部 mReader = 0; } try { Node node = mDataBuf.get(mReader); if (null != node && WRITED == node.flag) { node.flag = READED; mDataBuf.set(mReader, node); mReader--; return node.object; } else {// 已读空 } } catch (Exception e) {// 可能还未写过数据 } return null; } /** * 反相读取数据,无论当前位置的数据有没有读过,便可以重复读,不关心读/写指针位置,也不影响读写指针<br/> * @return 被拉取到的数据, 若是数据无效返回null */ public synchronized T pullBackNoCaseEmpty() { if (mReader < mCapacity) { if (mReader < 0) { mReader = mCapacity - 1; } } else if (mReader >= mCapacity) {// 读到尾部 mReader = 0; } try { Node node = mDataBuf.get(mReader); if (null != node && INVALID != node.flag) { // node.flag = READED; // mDataBuf.set(mReader, node); mReader--; return node.object; } else {// 无效数据(未写过) } } catch (Exception e) {// 可能还未写过数据 } return null; } /** * 缓冲区是否已满(对写操做而言) */ public synchronized boolean isFull() { try { Node n = mDataBuf.get(mWriter); if (null != n && WRITED == n.flag) { return true; } } catch (Exception e) { } return false; } /** * 缓冲区是否为空(对读操做而言) */ public synchronized boolean isEmpty() { if (mReader < mCapacity) { } else if (mReader >= mCapacity) {// 读到尾部 mReader = 0; } try { Node node = mDataBuf.get(mReader); if (null != node && WRITED == node.flag) { } else { return true; } } catch (Exception e) {// 可能未写入过数据 return true; } return false; } /** * 环形缓存容量 */ public synchronized int capacity() { return mCapacity; } /** * 环形缓存size, size与capacity不必定相同,当还未填充满时size<capacity,反之size=capacity */ public synchronized int size() { return mDataBuf.size(); } }
测试:java
RingBuffer<String> mRingBuffer = new RingBuffer<String>(10); new Thread(new Runnable() { int write = 0; String s; @Override public void run() { while (true) { s = "data: " + write; if (mRingBuffer.push(s)) { Log.e(TAG, "Write: " + s); write++; } else { Log.e(TAG, "Write: data full"); } // mRingBuffer.pushNoCaseFull(s); // write++; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { String s; @Override public void run() { while (true) { s = mRingBuffer.pull(); if (null != s) { Log.e(TAG, "Read: " + s); } else { Log.e(TAG, "Read: Data invalid or empty"); } // s = mRingBuffer.pullNoCaseEmpty(); // s = mRingBuffer.pullBack(); try { Thread.sleep(90); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start();