BufferPool 缓冲池类的理解,手写一个BufferPool 缓冲池

BufferPool 是一个用于管理字节缓冲区(ByteBuffer)的内存池实现,主要目的是减少频繁的内存分配和释放操作,提高内存使用效率。

主要成员变量

  • totalSize: 内存池总大小

  • slotSize: 标准槽位大小

  • free: 当前剩余可用内存大小

  • slotQueue: 存放可重用的固定大小(slotSize)的 ByteBuffer 队列

  • waiters: 等待内存分配的线程条件队列

  • lock: 用于同步控制的锁

核心方法

1. 构造函数 BufferPool(int totalSize, int slotSize)

初始化内存池的总大小和标准槽位大小,并设置初始可用内存为总大小。

2. allocate(int size, long timeout) 方法

申请指定大小的内存缓冲区:

  1. 首先检查申请大小是否合法

  2. 如果申请大小正好是 slotSize 且 slotQueue 中有可用缓冲区,直接返回

  3. 如果当前可用内存(包括可释放的固定缓冲区)足够,则分配新内存

  4. 如果内存不足,当前线程进入等待队列,超时或被唤醒后重试

  5. 在 finally 块中确保如果有等待线程且内存可用时唤醒下一个等待线程

3. deallocate(ByteBuffer byteBuffer) 方法

释放缓冲区:

  1. 如果缓冲区大小等于 slotSize,清空并放回 slotQueue 供重用

  2. 否则,直接增加可用内存大小

  3. 如果有等待线程,唤醒一个

4. freeUp(int size) 私有方法

当需要分配内存但当前空闲内存不足时,尝试从 slotQueue 中释放缓冲区来腾出空间。

设计特点

  1. 两种内存管理策略:

    • 对于 slotSize 大小的缓冲区:重用机制

    • 其他大小的缓冲区:直接分配/释放

  2. 公平等待:

    • 使用队列管理等待线程,避免饥饿
  3. 超时控制:

    • 支持带超时的内存申请
  4. 线程安全:

    • 使用 ReentrantLock 和 Condition 保证线程安全
java 复制代码
package com.zsy;


import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 字节缓冲区内存池实现类
 *
 * <p>本类实现了一个线程安全的字节缓冲区内存池,支持固定大小的槽位分配和释放,
 * 并提供带超时机制的缓冲区申请功能。</p>
 *
 * @author [email protected]
 */
public class BufferPool {

    /**
     * 内存池总容量(字节)
     */
    private final int totalSize;

    /**
     * 每个槽位的大小(字节)
     */
    private final int slotSize;

    /**
     * 当前空闲内存大小(字节)
     */
    private int free;

    /**
     * 可用槽位队列(先进先出)
     */
    private final Deque<ByteBuffer> slotQueue = new ArrayDeque<>();

    /**
     * 等待队列(存储等待内存分配的线程条件)
     */
    private final Deque<Condition> waiters = new ArrayDeque<>();

    /**
     * 可重入锁,用于线程同步
     */
    private final Lock lock = new ReentrantLock();

    /**
     * 构造函数
     *
     * @param totalSize 内存池总容量(字节)
     * @param slotSize 每个槽位的大小(字节)
     * @throws IllegalArgumentException 如果参数不合法(小于等于0)
     */
    public BufferPool(int totalSize, int slotSize) {
        if (totalSize <= 0 || slotSize <= 0) {
            throw new IllegalArgumentException("内存池大小和槽位大小必须大于0");
        }
        this.totalSize = totalSize;
        this.slotSize = slotSize;
        this.free = totalSize;
    }

    /**
     * 申请指定大小的字节缓冲区
     *
     * @param size 请求的缓冲区大小(字节)
     * @param timeout 最大等待时间(毫秒)
     * @return 分配到的ByteBuffer对象
     * @throws InterruptedException 如果线程在等待时被中断
     * @throws RuntimeException 如果请求大小不合法或超时未分配到内存
     */
    public ByteBuffer allocate(int size, long timeout) throws InterruptedException {
        // 方法实现...
        if (size > totalSize || size <= 0) {
            throw new RuntimeException("你的申请容量异常" + size);
        }
        lock.lock();
        try {
            if (size == slotSize && !slotQueue.isEmpty()) {
                return slotQueue.pollFirst();
            }
            if ((free + slotQueue.size() * slotSize) >= size) {
                freeUp(size);
                free -= size;
                return ByteBuffer.allocate(size);
            }
            Condition condition = lock.newCondition();
            waiters.addLast(condition);
            long remainTime = timeout;
            try {
                while (true) {
                    long start = System.currentTimeMillis();
                    boolean wakeup = condition.await(remainTime, TimeUnit.MILLISECONDS);
                    if (!wakeup) {
                        throw new RuntimeException("规定时间内不能申请需要的内存");
                    }
                    if (size == slotSize && !slotQueue.isEmpty()) {
                        return slotQueue.pollFirst();
                    }
                    if ((free + slotQueue.size() * slotSize) >= size) {
                        freeUp(size);
                        free -= size;
                        return ByteBuffer.allocate(size);
                    }
                    remainTime -= System.currentTimeMillis() - start;
                }
            } finally {
                waiters.remove(condition);
            }

        } finally {
            if (!waiters.isEmpty() && !(free == 0 && slotQueue.isEmpty())) {
                waiters.peekFirst().signal();
            }
            lock.unlock();
        }
    }

    /**
     * 释放字节缓冲区到内存池
     *
     * @param byteBuffer 要释放的ByteBuffer对象
     * @throws NullPointerException 如果参数为null
     */
    public void deallocate(ByteBuffer byteBuffer) {
        // 方法实现...
        lock.lock();
        try {
            if (byteBuffer.capacity() == this.slotSize) {
                byteBuffer.clear();
                this.slotQueue.addLast(byteBuffer);
            } else {
                free += byteBuffer.capacity();
            }
            if (!waiters.isEmpty()) {
                waiters.peekFirst().signal();
            }
        } finally {
            lock.unlock();
        }
    }

    /**
     * 内部方法:释放足够的内存以满足请求大小
     *
     * @param size 需要的内存大小
     */
    private void freeUp(int size) {
        // 方法实现...
        while (free < size && !slotQueue.isEmpty()) {
            free += slotQueue.pollFirst().capacity();
        }
    }
}
相关推荐
胖哥真不错1 分钟前
基于PyQt5和PaddleSpeech的中文语音识别系统设计与实现(Python)
python·毕业设计·语音识别·课程设计·paddlespeech·pyqt5·中文语音识别系统
昂子的博客3 分钟前
Springboot仿抖音app开发之Nacos 分布式服务与配置中心(进阶)
java·spring boot·redis·后端·mysql·ip
还是鼠鼠10 分钟前
JavaWeb RESTful 开发规范入门
java·数据库·spring boot·后端·spring·mybatis·restful
微信公众号:AI创造财富13 分钟前
Pyenv 跟 Conda 还有 Poetry 有什么区别?各有什么不同?
人工智能·python·conda·tensorflow
爱码少年22 分钟前
shel脚本重启Jar服务
java·jar
李艺为26 分钟前
framework.jar三个jar包的区别
java·pycharm·jar
范纹杉想快点毕业31 分钟前
Qt实现文本编辑器光标高亮技术
java·开发语言·c++·算法·系统架构
LBJ辉39 分钟前
9. CSS 引入方式
开发语言·前端·css
C语言小火车1 小时前
C语言酒店管理系统:完整源码与深度解析
c语言·开发语言
guwei6666661 小时前
多模态能解决什么样的业务场景?
java