继续上文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-----------------------------------------