环形缓存(java版)

本文介绍了作者根据自身需求实现的一个简单的Java环形缓存,指出其逻辑简洁但存在内存浪费的问题,并提供了在Android平台上的测试代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天看了一下同事的环形缓存,在百度了一下,发现大多数都是在比较读/写位置,我觉得这样不适合我,首先读/写位置比较逻辑比较复杂。

然后动手写了一个适合自己的(逻辑简单),但我写的这个也有个弱点:浪费内存 :-(



代码如下:

/**
 * 环形缓冲区<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();
    }
}


测试(测试平台android):

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


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值