继续上文Jetty源码-IO-BufferUtil ,接着讲解下Jetty ByteBufferPool的实现。
主要介绍ArrayByteBufferPool的实现,大概的原理是用Bucket数据来放要池化的ByteBuffer。桶的结构包含了它要池化ByteBuffer容量的大小Size 和 一个Queue (这里采用的是ConcurrentLinkedQueue,线程安全)。一个ByteBufferPool包含了两个Bucket[],一个用来放direct类型的ByteBuffer,一个用来放Heap类型的ByteBuffer。ByteBufferPool初始化的时候会把两个桶的每个成员都初始化。一个Bucket盛放对应相应capacity大小的的ByteBuffer。比如 我们ByteBufferPool池化可以放置最大容量为1024*60 到最小容量为0的ByteBuffer。对应的Bucket数组初始化就是60个桶,从 1024大小的,2048大小的,3072大小的.....1024*60大小的桶,当我们需要ByteBuffer时,我们只需根据容量到相应的桶中的Queue取出来即可。
以下是具体代码
接口类:
public interface ByteBufferPool { /** * 获取指定大小的ByteBuffer. * @param size * @param direct 是否用direct内存 * @return */ public ByteBuffer acquire(int size,boolean direct); /** * 返还ByteBuffer,使之重用 * @param buffer */ public void release(ByteBuffer buffer); //ByteBufferPool的工具类,我们可以方便的用它来操作ByteBufferPool,当然不用也可以,大家可以先直接跳过 //因为这个类有点会误导大家的思路。可以直接看ArrayByteBufferPool的实现就OK public static class Lease{ private final ByteBufferPool byteBufferPool; private final List<ByteBuffer> buffers; private final List<Boolean>recycles; public Lease(ByteBufferPool byteBufferPool, List<ByteBuffer> buffers, List<Boolean> recycles) { this.byteBufferPool = byteBufferPool; this.buffers = buffers; this.recycles = recycles; } public ByteBuffer acquire(int capacity,boolean direct){ ByteBuffer buffer=byteBufferPool.acquire(capacity,direct); BufferUtil.clearToFill(buffer); return buffer; } //预先王ByteBuffer list中插入一个ByteBuffer public void prepend(ByteBuffer buffer,boolean recycle){ insert(0, buffer, recycle); } public void insert(int index, ByteBuffer buffer, boolean recycle) { buffers.add(index,buffer); recycles.add(index,recycle); } public void append(ByteBuffer buffer, boolean recycle) { buffers.add(buffer); recycles.add(recycle); } public List<ByteBuffer> getByteBuffers() { return buffers; } //buffer list 所有剩余长度 public long getTotalLength() { long length = 0; for (int i = 0; i < buffers.size(); ++i) length += buffers.get(i).remaining(); return length; } public int getSize() { return buffers.size(); } //释放所有可以循环利用的ByteBuffer public void recycle() { for (int i = 0; i < buffers.size(); ++i) { ByteBuffer buffer = buffers.get(i); if (recycles.get(i)) byteBufferPool.release(buffer); } buffers.clear(); recycles.clear(); } } }
具体的ArrayByteBufferPool的实现
public class ArrayByteBufferPool implements ByteBufferPool { private final int _min; private final Bucket[]_direct; private final Bucket[]_indirect; private final int _inc; public ArrayByteBufferPool() { this(0,1024,64*1024); } public ArrayByteBufferPool(int minSize, int increment, int maxSize) { //最小size不能大于增量 if (minSize>=increment) throw new IllegalArgumentException("minSize >= increment"); //最大size 必须是增量的整数倍,并且增量不能大于最大的size if ((maxSize%increment)!=0 || increment>=maxSize) throw new IllegalArgumentException("increment must be a divisor of maxSize"); _min=minSize; _inc=increment; //初始化 maxSize/increment个桶,包含直接内存的与heap的 _direct=new Bucket[maxSize/increment]; _indirect=new Bucket[maxSize/increment]; int size=0; for (int i=0;i<_direct.length;i++) { size+=_inc; _direct[i]=new Bucket(size); _indirect[i]=new Bucket(size); } } @Override public ByteBuffer acquire(int size, boolean direct) { //根据size找到对应size的桶 Bucket bucket = bucketFor(size,direct); //如果queue中存在ByteBuffer,则直接返回 ByteBuffer buffer = bucket==null?null:bucket._queue.poll(); //初次使用 桶中的queue没有 ByteBuffer if (buffer == null){ //(bucket==null)如果是由于size 超过pool的最大size,造成没有相应的桶 int capacity = bucket==null?size:bucket._size; //分配相应size的ByteBuffer; buffer = direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity); } return buffer; } @Override public void release(ByteBuffer buffer) { if (buffer!=null){ Bucket bucket = bucketFor(buffer.capacity(),buffer.isDirect()); if (bucket!=null){ BufferUtil.clear(buffer); //关键:这步是把相应size的ByteBuffer放到相应的size的桶中,byteBuffer入队,用来重用 bucket._queue.offer(buffer); } } } //清空byteBuffer pool public void clear(){ for (int i=0;i<_direct.length;i++){ _direct[i]._queue.clear(); _indirect[i]._queue.clear(); } } //根据size寻找 桶 private Bucket bucketFor(int size,boolean direct) { if (size<=_min) return null; int b=(size-1)/_inc; if (b>=_direct.length) return null; Bucket bucket = direct?_direct[b]:_indirect[b]; return bucket; } public static class Bucket{ public final int _size; public final Queue<ByteBuffer> _queue= new ConcurrentLinkedQueue<>(); Bucket(int size) { _size=size; } @Override public String toString() { return String.format("Bucket@%x{%d,%d}",hashCode(),_size,_queue.size()); } } }
简单的测试:
public class ByteBufferPoolTest { public static void main(String[]args){ ByteBufferPool.Lease lease = new ByteBufferPool.Lease(new ArrayByteBufferPool(), new ArrayList<>(), new ArrayList<>()); ByteBuffer buffer1=lease.acquire(100, false); lease.append(buffer1,true); buffer1.put("robin yao".getBytes()); BufferUtil.flipToFlush(buffer1, 0); System.out.println(new String(buffer1.array())); lease.recycle(); ByteBuffer buffer2=lease.acquire(100, false); //是否是同一个 System.out.println(buffer1==buffer2); } }
除了ArrayByteBufferPool的实现,还有MappedByteBufferPool的实现,利用ConcurrentMap实现,这里不做介绍
转发请标注来源:http://my.oschina.net/robinyao/blog/403334
END-----------------------------------------