1. 程式人生 > >java環形緩衝區

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

測試:

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