Netty-对象池原理

归档


参考


单元测试

public class ObjPoolTest {
    private static final Recycler<User> RECYCLER = new Recycler<User>() {
        @Override
        protected User newObject(Handle<User> handle) {
            User user = new User(handle);
            user.name = "init-" + LocalTime.now();
            return user;
        }
    };

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

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

        public void recycle() {
            handle.recycle(this);       // 回收对象 sign_tm_10
        }
    }

    @Test
    public void test() throws InterruptedException {
        User user1 = RECYCLER.get();    // 1、从对象池获取 User 对象 sign_tm_01
        user1.name = "hello";           // 2、设置 User 对象的属性
        user1.recycle();                // 3、回收对象到对象池
        // user1.recycle();             // 如果不调用 recycle(), 则会创建新的对象

        Runnable run = () -> {
            User user2 = RECYCLER.get();// 4、从对象池获取对象
            System.out.println("\nCur-Thread-Name: " + Thread.currentThread().getName());
            System.out.println(user2.name);
            System.out.println(user1 == user2);
        };
        run.run();

        Thread thread1 = new Thread(run, "test-01");
        thread1.start();
        thread1.join();
    }

    @Test
    public void testQueue() {
        MpscChunkedArrayQueue<Integer> queue = new MpscChunkedArrayQueue<>(2, 8);
        for (int i = 0; i < 10; i++) {
            queue.relaxedOffer(i);
            queue.offer(i);
        }
        System.out.println(queue.size());
        queue.forEach(i -> System.out.println("i: " + i));
    }
}

原理

类结构

  • io.netty.util.Recycler
/*** 再循环器(可理解为对象池 Pool) */
public abstract class Recycler<T> {
    private final int maxCapacityPerThread; // def: 4096
    private final int interval;             // def: 8
    private final int chunkSize;            // def: 32

    // 线程变量
    private final FastThreadLocal<LocalPool<T>> threadLocal = new FastThreadLocal<LocalPool<T>>() {
        @Override
        protected LocalPool<T> initialValue() {
            return new LocalPool<T>(maxCapacityPerThread, interval, chunkSize);
        }
    };

    /*** 对象池 */
    private static final class LocalPool<T> implements MessagePassingQueue.Consumer<DefaultHandle<T>> {
        private final ArrayDeque<DefaultHandle<T>> batch;                       // 一级缓存 sign_f_20
        private volatile MessagePassingQueue<DefaultHandle<T>> pooledHandles;   // 二级缓存 sign_f_21
        private int ratioCounter;   // 计数器

        LocalPool(int maxCapacity, int ratioInterval, int chunkSize) {
            batch = new ArrayDeque<DefaultHandle<T>>(chunkSize);
            // 相当于:
            // pooledHandles = new MpscChunkedArrayQueue<T>(chunkSize, maxCapacity);
            pooledHandles = (MessagePassingQueue<DefaultHandle<T>>) newMpscQueue(chunkSize, maxCapacity);
            ratioCounter = ratioInterval;
        }
    }

    /*** 对象句柄 */
    private static final class DefaultHandle<T> extends EnhancedHandle<T> {
        private volatile int state;             // 状态(值为: STATE_CLAIMED = 0, STATE_AVAILABLE = 1) sign_f_11
        private final LocalPool<T> localPool;   // (归属的)对象池
        private T value;                        // (绑定的)对象 sign_f_10

        DefaultHandle(LocalPool<T> localPool) {
            this.localPool = localPool;
        }
    }
}

调用链

  • io.netty.util.Recycler
    // 获取对象 sign_tm_01
    public final T get() {
        ... // 省略为 0 容量的处理
        LocalPool<T> localPool = threadLocal.get();
        DefaultHandle<T> handle = localPool.claim(); // 拿取句柄 sign_m_10
        T obj;
        if (handle == null) {               // 第一次为 null
            handle = localPool.newHandle(); // 创建句柄 sign_m_20
            if (handle != null) {
                obj = newObject(handle);    // 创建对象
                handle.set(obj);            // 绑定对象到句柄(赋值给 sign_f_10)
            } else {
                obj = newObject((Handle<T>) NOOP_HANDLE);
            }
        } else {
            obj = handle.get();             // 返回池中可用的对象
        }

        return obj;
    }
  • io.netty.util.Recycler.LocalPool
        // 拿取对象句柄 sign_m_10
        DefaultHandle<T> claim() {
            MessagePassingQueue<DefaultHandle<T>> handles = pooledHandles;
            if (handles == null) {
                return null;
            }
            if (batch.isEmpty()) {
                /**
                 * 从池里拿(第一次都没数据)。
                 * 池里有的话,批量拿取 chunkSize(32) 个,回调 sign_m_11,
                 *   添加到 batch 里面。
                 */
                handles.drain(this, chunkSize);
            }
            DefaultHandle<T> handle = batch.pollFirst();
            if (null != handle) {
                handle.toClaimed(); // 改句柄状态 sign_f_11
            }
            return handle; // 第一次返回 null
        }

        // jctools 钩子函数 sign_m_11
        @Override
        public void accept(DefaultHandle<T> e) {
            batch.addLast(e);
        }

        // 创建对象句柄 sign_m_20
        DefaultHandle<T> newHandle() {
            if (++ratioCounter >= ratioInterval) { // 第一次会进入
                /**
                 * 进入后清空计数器,
                 * 相当于每 ratioInterval(8) 次才创建一个句柄。
                 */
                ratioCounter = 0;
                return new DefaultHandle<T>(this); // 创建句柄
            }
            return null; // 相当于不进行缓存
        }

        // 释放对象 sign_m_30 
        void release(DefaultHandle<T> handle, boolean guarded) {
            if (guarded) {
                handle.toAvailable(); // 设置状态 sign_f_11
            } else {
                handle.unguardedToAvailable();
            }
            Thread owner = this.owner;
            if (owner != null && Thread.currentThread() == owner && batch.size() < chunkSize) {
                /**
                 * 当前线程是拥有者且一级缓存数小于 chunkSize(32) 个,
                 * 则加入到一级缓存 sign_f_20
                 */
                accept(handle);
            } else if (owner != null && isTerminated(owner)) {  // 线程已终止,则清空二级缓存 sign_f_21
                this.owner = null;
                pooledHandles = null;
            } else {
                MessagePassingQueue<DefaultHandle<T>> handles = pooledHandles;
                if (handles != null) {
                    handles.relaxedOffer(handle);               // 添加到二级缓存 sign_f_21
                }
            }
        }
  • io.netty.util.Recycler.DefaultHandle
        // 回收对象 sign_tm_10
        @Override
        public void recycle(Object object) {
            if (object != value) { // 回收的对象不是自己绑定的,则报错
                throw new IllegalArgumentException("object does not belong to handle");
            }
            localPool.release(this, true); // 释放对象 sign_m_30
        }

总结

  • 只能在当前线程有用
  • 每 8 次才创建一个句柄加入到对象池
  • 设置有两级缓存,一级缓存默认 32 个,二级缓存默认 4096 个(且最多只缓存前面的 4096 个)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值