java環形緩衝區
阿新 • • 發佈:2018-12-13
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(); } }
測試:
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();