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();