CodecOutputList是什么
你可以简单的理解为一个列表,里面存放我们解码后的消息,很多解码器里都会用到,所以还是要知道下,我们解码后的对象就是放入这个表里的,解码后传递给后续处理器的也是这里面的消息对象。
里面放的消息就是我们处理器经常用到的msg
:
大致结构图就是这个样子的:
重要属性
看看里面放着什么东西,首先他会有一个回收器,这个是跟线程本地变量挂钩的,就是一个池化的作用。里面存放着一个数组就是解码后的消息对象。
//回收器
private final CodecOutputListRecycler recycler;
private int size;//拥有的对象个数
private Object[] array;//对象数组
private boolean insertSinceRecycled;//是否有对象加入数组过
回收器
首先定义了一个回收器接口,然后创建了一个啥都没干的回收器,等GC
处理了。
private interface CodecOutputListRecycler {
void recycle(CodecOutputList codecOutputList);
}
private static final CodecOutputListRecycler NOOP_RECYCLER = new CodecOutputListRecycler() {
@Override
public void recycle(CodecOutputList object) {
// drop on the floor and let the GC handle it.
}
};
线程本地变量
线程本地变量就可以跟着线程一起存活着,等于有了池化的作用,而且是线程安全的,存在IO
线程里。默认初始化是生成一个CodecOutputLists
,这个是什么,我猜就是个CodecOutputList
集合。
private static final FastThreadLocal<CodecOutputLists> CODEC_OUTPUT_LISTS_POOL =
new FastThreadLocal<CodecOutputLists>() {
@Override
protected CodecOutputLists initialValue() throws Exception {
// 16 CodecOutputList per Thread are cached.
return new CodecOutputLists(16);
}
};
CodecOutputLists
里面放着很多CodecOutputList
,然后实现了回收器接口CodecOutputListRecycler
,用来回收CodecOutputList
。
内部创建了一个CodecOutputList
数组,默认每个CodecOutputList
可以存放16
个消息对象。如果获取的时候没有CodecOutputList
了,就会创建一个不缓存的CodecOutputList
,默认存放4
个消息对象。
private static final class CodecOutputLists implements CodecOutputListRecycler {
private final CodecOutputList[] elements;
private final int mask;//取余掩码
private int currentIdx;//当前索引
private int count;//列表个数
CodecOutputLists(int numElements) {
elements = new CodecOutputList[MathUtil.safeFindNextPositivePowerOfTwo(numElements)];//创建2的幂次个列表
for (int i = 0; i < elements.length; ++i) {//初始化
// Size of 16 should be good enough for the majority of all users as an initial capacity.
elements[i] = new CodecOutputList(this, 16);
}
count = elements.length;
currentIdx = elements.length;
mask = elements.length - 1;
}
//如果没缓存就创建一个不缓存的,默认创建长度为4的数组
public CodecOutputList getOrCreate() {
if (count == 0) {
// Return a new CodecOutputList which will not be cached. We use a size of 4 to keep the overhead
// low.
return new CodecOutputList(NOOP_RECYCLER, 4);
}
--count;
int idx = (currentIdx - 1) & mask;//从后往前取,取模,算出索引位置
CodecOutputList list = elements[idx];
currentIdx = idx;
return list;
}
//回收CodecOutputList
@Override
public void recycle(CodecOutputList codecOutputList) {
int idx = currentIdx;
elements[idx] = codecOutputList;
currentIdx = (idx + 1) & mask;//当前索引增加,取模
++count;
assert count <= elements.length;
}
}
newInstance获取CodecOutputList对象
外面是通过CodecOutputList 的newInstance来获得对象,其实是从线程本地变量的CodecOutputLists
里获取的。
static CodecOutputList newInstance() {
return CODEC_OUTPUT_LISTS_POOL.get().getOrCreate();
}
构造方法
构造方法的时候就会传入回收器和消息对象数组的长度。
private CodecOutputList(CodecOutputListRecycler recycler, int size) {
this.recycler = recycler;
array = new Object[size];
}
get有检查获取消息对象
有检查的获取,外部使用
@Override
public Object get(int index) {
checkIndex(index);
return array[index];
}
getUnsafe无检查获取消息对象
少了检查,内部使用的。
Object getUnsafe(int index) {
return array[index];
}
insert插入对象到指定位置
直接把对象放入指定数组的位置,设置标记。
//放入数组
private void insert(int index, Object element) {
array[index] = element;
insertSinceRecycled = true;//有放入过了
}
add添加对象到最后
直接插入,如果越界就扩容,再插入。
@Override
public boolean add(Object element) {
checkNotNull(element, "element");
try {
insert(size, element);//插入
} catch (IndexOutOfBoundsException ignore) {
expandArray();//扩容
insert(size, element);//插入
}
++ size;
return true;
}
add添加对象到指定位置
先判断是否要扩容,然后进行数组拷贝,也就是移动里面的元素,腾出指定位置,然后插入指定位置。
@Override
public void add(int index, Object element) {
checkNotNull(element, "element");
checkIndex(index);
if (size == array.length) {
expandArray();//扩容
}
if (index != size) {
System.arraycopy(array, index, array, index + 1, size - index);//拷贝指定位置以及之后的对象,就是向后移动数组
}
insert(index, element);
++ size;
}
remove删除指定位置的对象
把指定位置的对象取出来,然后移动数组,最后位置清空,并返回删除的对象。
@Override
public Object remove(int index) {
checkIndex(index);
Object old = array[index];
int len = size - index - 1;
if (len > 0) {
System.arraycopy(array, index + 1, array, index, len);//向前移动数组
}
array[-- size] = null;//最后位置清空
return old;
}
clear清空
只是把个数清空了。真正的删除元素是在recycle
中的。
@Override
public void clear() {
size = 0;
}
recycle清空对象并回收到CodecOutputLists中
void recycle() {
for (int i = 0 ; i < size; i ++) {
array[i] = null;
}
size = 0;
insertSinceRecycled = false;
recycler.recycle(this);
}
expandArray扩容数组
扩容,每次2
倍,直到溢出位置。
private void expandArray() {
// double capacity
int newCapacity = array.length << 1;
if (newCapacity < 0) {//溢出了
throw new OutOfMemoryError();
}
Object[] newArray = new Object[newCapacity];
System.arraycopy(array, 0, newArray, 0, array.length);
array = newArray;
}