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 gongxuanzhangmelt@gmail.com
 */
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();
        }
    }
}
相关推荐
fire-flyer38 分钟前
Spring Boot 源码解析之 Logging
java·spring boot·spring·log4j·logging
CodeCraft Studio40 分钟前
Excel处理控件Aspose.Cells教程:使用 Python 在 Excel 中创建甘特图
python·excel·项目管理·甘特图·aspose·aspose.cells
papership43 分钟前
【入门级-C++程序设计:12、文件及基本读写-文件的基本概念&文本文件的基本操作】
开发语言·c++·青少年编程
SaleCoder2 小时前
用Python构建机器学习模型预测股票趋势:从数据到部署的实战指南
开发语言·python·机器学习·python股票预测·lstm股票模型·机器学习股票趋势
KoiHeng2 小时前
部分排序算法的Java模拟实现(复习向,非0基础)
java·算法·排序算法
cui_hao_nan5 小时前
JVM——如何对java的垃圾回收机制调优?
java·jvm
熟悉的新风景7 小时前
springboot项目或其他项目使用@Test测试项目接口配置-spring-boot-starter-test
java·spring boot·后端
心平愈三千疾7 小时前
学习秒杀系统-实现秒杀功能(商品列表,商品详情,基本秒杀功能实现,订单详情)
java·分布式·学习
玩代码7 小时前
备忘录设计模式
java·开发语言·设计模式·备忘录设计模式
BUTCHER58 小时前
Docker镜像使用
java·docker·容器