Netty4 Recycler

Recycler

Recycler是Netty经常使用的对象池抽象类,通过重用对象,能够避免频繁创建对象和销毁对象带来的损耗。

1. Recycler 抽象类介绍

1. 使用了FastThreadLocal

    // 每个线程都有自己的stack
    private final FastThreadLocal<Stack<T>> threadLocal = new FastThreadLocal<Stack<T>>() {
        @Override
        protected Stack<T> initialValue() {
            return new Stack<T>(Recycler.this, Thread.currentThread(), maxCapacityPerThread, maxSharedCapacityFactor,
                    ratioMask, maxDelayedQueuesPerThread);
        }

        @Override
        protected void onRemoval(Stack<T> value) {
            // Let us remove the WeakOrderQueue from the WeakHashMap directly if its safe to remove some overhead
            if (value.threadRef.get() == Thread.currentThread()) {
               if (DELAYED_RECYCLED.isSet()) {
                   DELAYED_RECYCLED.get().remove(value);
               }
            }
        }
    };

    // 每个线程stack对应的WeakOrderQueue, WeakOrderQueue主要记录其他线程回收对象
    private static final FastThreadLocal<Map<Stack<?>, WeakOrderQueue>> DELAYED_RECYCLED =
            new FastThreadLocal<Map<Stack<?>, WeakOrderQueue>>() {
        @Override
        protected Map<Stack<?>, WeakOrderQueue> initialValue() {
            return new WeakHashMap<Stack<?>, WeakOrderQueue>();
        }
    };

 

2.  核心方法

protected abstract T newObject(Handle<T> handle);

public final T get();

2. 怎么使用

    static class User {
        private String name;
        private Recycler.Handle<User> handle;

        public User(Recycler.Handle<User> handle) {
            this.handle = handle;
        }

        public void recycle() {
            handle.recycle(this);
        }
    }

    private static final Recycler<User> userRecycler = new Recycler<User>() {
        @Override
        protected User newObject(Handle<User> handle) {
            return new User(handle);
        }
    };

    @Test
    public void test() {
        // 1、从对象池获取对象
        User user1 = userRecycler.get();
        // 2、设置对象并使用
        user1.setName("hello recycle");
        // 3、对象恢复出厂设置
        user1.setName(null);
        // 4、回收对象到对象池
        user1.recycle();
        // 5、从回收池获取对象
        User user2 = userRecycler.get();
        System.out.println(user1 == user2);
    }

测试结果   true

3. get()方法

    public final T get() {
        if (maxCapacityPerThread == 0) {
            return newObject((Handle<T>) NOOP_HANDLE);
        }
        Stack<T> stack = threadLocal.get();
        DefaultHandle<T> handle = stack.pop();
        if (handle == null) {
            handle = stack.newHandle();
            handle.value = newObject(handle);
        }
        return (T) handle.value;
    }

1.若maxCapacityPerThread =0时,就返回一个空实现recycle方法的Handle实体类

2.获取当前线程的Stack    Stack<T> stack = threadLocal.get(); 这个利用FastThreadLocal

3.stack.pop()

        DefaultHandle<T> pop() {
            int size = this.size;
            if (size == 0) {
                if (!scavenge()) {
                    return null;
                }
                size = this.size;
            }
            size --;
            DefaultHandle ret = elements[size];
            elements[size] = null;
            if (ret.lastRecycledId != ret.recycleId) {
                throw new IllegalStateException("recycled multiple times");
            }
            ret.recycleId = 0;
            ret.lastRecycledId = 0;
            this.size = size;
            return ret;
        }

Stack实体类主要实现方式是数组形式,当size=0时,说明当前线程中stack没有回收到对象,直接调用scavenge()方法,这个后面会去分析,当size>0时,直接从数组中取出对象。

4.当pop返回null,直接调用newHandle()

4. Handle.recycel()

        public void recycle(Object object) {
            if (object != value) {
                throw new IllegalArgumentException("object does not belong to handle");
            }
            stack.push(this);
        }

一般回收的逻辑是由用户去写,Handel不会去处理,Handle.recycel()主要是执行stack.push(this);

stack.push()

        void push(DefaultHandle<?> item) {
            Thread currentThread = Thread.currentThread();
            if (threadRef.get() == currentThread) {
                // The current Thread is the thread that belongs to the Stack, we can try to push the object now.
                pushNow(item);
            } else {
                // The current Thread is not the one that belongs to the Stack
                // (or the Thread that belonged to the Stack was collected already), we need to signal that the push
                // happens later.
                pushLater(item, currentThread);
            }
        }

1.若是当前线程则表示自己回收对象,调用pushNow()

        private void pushNow(DefaultHandle<?> item) {
            if ((item.recycleId | item.lastRecycledId) != 0) {
                throw new IllegalStateException("recycled already");
            }
            item.recycleId = item.lastRecycledId = OWN_THREAD_ID;

            int size = this.size;
            if (size >= maxCapacity || dropHandle(item)) {
                // Hit the maximum capacity or should drop - drop the possibly youngest object.
                return;
            }
            if (size == elements.length) {
                elements = Arrays.copyOf(elements, min(size << 1, maxCapacity));
            }

            elements[size] = item;
            this.size = size + 1;
        }

1.1 判断当前size是否大于最大容量

1.2 dropHandle()

        boolean dropHandle(DefaultHandle<?> handle) {
            // 1.判断有没有被回收
            if (!handle.hasBeenRecycled) {
                // 2. handleRecycleCount 初始值是-1,正常情况是0
                // 若不是0,表示已经被回收了,直接放弃
                if ((++handleRecycleCount & ratioMask) != 0) {
                    // Drop the object.
                    return true;
                }
                handle.hasBeenRecycled = true;
            }
            return false;
        }

1.3 如果数组满了需要扩容一倍,最大 4096(默认) 

2. 若不是当前线程则表示其他多线程回收对象,调用pushLater()

        private void pushLater(DefaultHandle<?> item, Thread thread) {
            Map<Stack<?>, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get();
            WeakOrderQueue queue = delayedRecycled.get(this);
            if (queue == null) {
                if (delayedRecycled.size() >= maxDelayedQueues) {
                    delayedRecycled.put(this, WeakOrderQueue.DUMMY);
                    return;
                }
                if ((queue = WeakOrderQueue.allocate(this, thread)) == null) {
                    return;
                }
                delayedRecycled.put(this, queue);
            } else if (queue == WeakOrderQueue.DUMMY) {
                return;
            }

            queue.add(item);
        }

2.1 获取当前线程delayedRecycled

2.2 根据stack,去获取WeakOrderQueue,注意这个stack不是当前线程的stack,这样每个线程可以和其他线程通过stack关联WeakOrderQueue,这样才能达到其他线程可以回收当前线程的对象,会存储在WeakOrderQueue中link,而Link类中包含DefaultHandle<?>[]  默认是16个

2.3 获取的queue为null时,先判断delayedRecycled.size() >= maxDelayedQueues,然后尝试创建一个queue,链接到这个 Stack 的 head 节点前

2.4 最终将回收对象放到queue中

        void add(DefaultHandle<?> handle) {
            handle.lastRecycledId = id;

            Link tail = this.tail;
            int writeIndex;
            if ((writeIndex = tail.get()) == LINK_CAPACITY) {
                if (!reserveSpace(availableSharedCapacity, LINK_CAPACITY)) {
                    // Drop it.
                    return;
                }
                // We allocate a Link so reserve the space
                this.tail = tail = tail.next = new Link();

                writeIndex = tail.get();
            }
            tail.elements[writeIndex] = handle;
            handle.stack = null;
            tail.lazySet(writeIndex + 1);
        }

1.如果这个 tiail 节点满了,查看是否还有共享空间,如果没了,就丢弃这个实例

2.反之新建一个 Link,追加到 tail 节点的尾部。然后,将数据插入新 tail 的数组

5. stack.scavenge()

这个主要从其他线程中,看有没有回收的线程

        boolean scavenge() {
            // continue an existing scavenge, if any
            if (scavengeSome()) {
                return true;
            }

            // reset our scavenge cursor
            prev = null;
            cursor = head;
            return false;
        }

        boolean scavengeSome() {
            WeakOrderQueue prev;
            WeakOrderQueue cursor = this.cursor;
            if (cursor == null) {
                prev = null;
                cursor = head;
                if (cursor == null) {
                    return false;
                }
            } else {
                prev = this.prev;
            }

            boolean success = false;
            do {
                if (cursor.transfer(this)) {
                    success = true;
                    break;
                }
                WeakOrderQueue next = cursor.next;
                if (cursor.owner.get() == null) {
                    if (cursor.hasFinalData()) {
                        for (;;) {
                            if (cursor.transfer(this)) {
                                success = true;
                            } else {
                                break;
                            }
                        }
                    }

                    if (prev != null) {
                        prev.setNext(next);
                    }
                } else {
                    prev = cursor;
                }

                cursor = next;

            } while (cursor != null && !success);

            this.prev = prev;
            this.cursor = cursor;
            return success;
        }

1.拿到这个 stack 的 queue,调用这个 queue 的 transfer 方法,如果成功,结束循环。

2.如果 queue 所在的线程被回收了,就将这个线程对应的 queue 中的所有数据全部转移到 stack 中。

总结:

Netty实现了一个相对轻量的对象池。通过使用 threadLocal,避免了多线程下取数据时可能出现的线程安全问题.

下面就是Netty设计recycle图

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值