2023-09-13
原文作者:https://blog.csdn.net/wangwei19871103/category_9681495_2.html 原文地址: https://blog.csdn.net/wangwei19871103/article/details/104533917

CodecOutputList是什么

你可以简单的理解为一个列表,里面存放我们解码后的消息,很多解码器里都会用到,所以还是要知道下,我们解码后的对象就是放入这个表里的,解码后传递给后续处理器的也是这里面的消息对象。

202309132207224891.png
里面放的消息就是我们处理器经常用到的msg

202309132207232882.png
大致结构图就是这个样子的:

202309132207240103.png

重要属性

看看里面放着什么东西,首先他会有一个回收器,这个是跟线程本地变量挂钩的,就是一个池化的作用。里面存放着一个数组就是解码后的消息对象。

     //回收器
        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;
        }
阅读全文