java環形緩衝區

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();
相關文章
相關標籤/搜索