Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)—->第3节: recycler的使用和创建…

释放双眼,带上耳机,听听看~!

Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)—->第3节: recycler的使用和创建

 

Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler

 

第三节: recycler的使用和创建

** **

这一小节开始学习
recycler相关的知识
, recycler是
netty实现的一个轻量级对象回收站
, 在
netty中
, recycler的使用也是相当之频繁的

recycler
作用是保证了对象的循环利用
, 对象使用完可以通过
recycler回收
, 需要再次使用则从对象池中取出
, 不用每次都创建新对象从而减少对系统资源的占用
, 同时也减轻了
gc的压力

 

这里看一个示例
:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1public class RecyclerDemo {
2    private static final Recycler<User> RECYCLER = new Recycler<User>() {
3        @Override
4        protected User newObject(Handle<User> handle) {
5            return new User(handle);
6        }
7    };
8    static class User{
9        private final Recycler.Handle<User> handle;
10        public User(Recycler.Handle<User> handle){
11            this.handle=handle;
12        }
13        public void recycle(){
14            handle.recycle(this);
15        }
16    }
17    public static void main(String[] args){
18        User user1 = RECYCLER.get();
19        user1.recycle();
20        User user2 = RECYCLER.get();
21        user2.recycle();
22        System.out.println(user1==user2);
23    }
24}
25

首先定义了一个
Recycler的成员变量
RECYCLER, 在匿名内部类中重写了
newObject方法
, 也就是创建对象的方法
, 该方法就是用户自定义的

这里
newObject返回的
new User(handle), 代表当回收站没有此类对象的时候
, 可以通过这种方式创建对象

 

成员变量
RECYCLER, 可以用来对此类对象的回收和再利用

 

定一个了一个静态内部类
User, User中有个成员变量
handle, 在构造方法中为其赋值
, handle的作用
, 就是用于对象回收的

并且定义了一个方法
recycle, 方法体中通过
handle.recycle(this)这种方式将自身对象进行回收
, 通过这步操作
, 就可以将对象回收到
Recycler中

以上逻辑先做了解
, 之后会进行详细分析


main方法中
, 通过
RECYCLER的
get方法获取一个
user, 然后进行回收

再通过
get方法将回收站的对象取出
, 再次进行回收
, 最后判断两次取出的对象是否为一个对象
, 最后结果输出为
true

以上
demo就可以说明
Recycler的回收再利用的功能

 

简单介绍了
demo, 我们就详细的分析
Recycler的机制

 


Recycler的类的源码中
, 我们看到这一段逻辑

:


1
2
3
4
5
6
7
8
1private final FastThreadLocal<Stack<T>> threadLocal = new FastThreadLocal<Stack<T>>() {
2    @Override
3    protected Stack<T> initialValue() {
4        return new Stack<T>(Recycler.this, Thread.currentThread(), maxCapacityPerThread, maxSharedCapacityFactor,
5                ratioMask, maxDelayedQueuesPerThread);
6    }
7};
8

这一段逻辑我们并不陌生
, 在上一小节的学习中我们知道
, 这里用于保存线程共享对象
, 而这里的共享对象
, 就是一个
Stack类型的对象

 

每个
stack中维护着一个
DefaultHandle类型的数组
, 用于盛放回收的对象
, 有关
stack和线程的关系如图所示:

 

Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)---->第3节: recycler的使用和创建...

8-3-1

也就是说在每个
Recycler中
, 都维护着一个线程共享的栈
, 用于对一类对象的回收

 

跟到
Stack的构造方法中

:


1
2
3
4
5
6
7
8
9
10
11
1Stack(Recycler<T> parent, Thread thread, int maxCapacity, int maxSharedCapacityFactor,
2      int ratioMask, int maxDelayedQueues) {
3    this.parent = parent;
4    this.thread = thread;
5    this.maxCapacity = maxCapacity;
6    availableSharedCapacity = new AtomicInteger(max(maxCapacity / maxSharedCapacityFactor, LINK_CAPACITY));
7    elements = new DefaultHandle[min(INITIAL_CAPACITY, maxCapacity)];
8    this.ratioMask = ratioMask;
9    this.maxDelayedQueues = maxDelayedQueues;
10}
11

首先介绍几个构造方法中初始化的关键属性:

属性
parent表示
Reclycer对象自身

属性
thread表示当前
stack绑定的哪个线程

属性
maxCapacity表示当前
stack的最大容量
, 表示
stack最多能盛放多少个元素

属性
elements, 就表示
stack中存储的对象
, 类型为
DefaultHandle, 可以被外部对象引用
, 从而实现回收

属性
ratioMask是用来控制对象回收的频率的
, 也就是说每次通过
Reclycer回收对象的时候
, 不是每次都会进行回收
, 而是通过该参数控制回收频率

 

属性
maxDelayedQueues, 这里稍微有些复杂
, 在很多时候
, 一个线程创建的对象
, 有可能会被另一个线程所释放
, 而另一个线程释放的对象是不会放在当前线程的
stack中的
, 而是会存放在一个叫做
WeakOrderQueue的数据结构中
, 里面也是存放着一个个
DefaultHandle, WeakOrderQueue会存放线程
1创建的并且在线程
2进行释放的对象

这里只是稍作了解
, 之后的会对此做详细剖析
, 这里我们只需知道
, maxDelayedQueues属性的意思就是我这个线程能回收几个其他创建的对象的线程, 假设当前线程是线程1, 
maxDelayedQueues为2, 那么我线程1回收了线程2创建的对象, 又回收了线程3创建的对象, 那么不可能回收线程4创建的对象了, 因为
maxDelayedQueues2, 我只能回收两个线程创建的对象

属性
availableSharedCapacity, 表示在线程
1中创建的对象
, 在其他线程中缓存的最大个数
, 同样
, 相关逻辑会在之后的内容进行剖析

另外介绍两个没有在构造方法初始化的属性:


1
2
3
1private WeakOrderQueue cursor, prev;
2private volatile WeakOrderQueue head;
3

这里相当于指针
, 用于指向
WeakOrderQueue的
, 这里也是稍作了解
, 之后会进行详细剖析

 

 

有关
stack异线程之间对象的关系如图所示
(简略
):

Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)---->第3节: recycler的使用和创建...

8-3-2

我们再继续介绍
Recycler的构造方法
, 同时熟悉有关
stack各个参数的默认值:


1
2
3
4
1protected Recycler() {
2    this(DEFAULT_MAX_CAPACITY_PER_THREAD);
3}
4

这里调用了重载的构造方法
, 并传入了参数
DEFAULT_MAX_CAPACITY_PER_THREAD

DEFAULT_MAX_CAPACITY_PER_THREAD
的默认值是
32768, 在
static块中被初始化的
, 我们可以跟进去自行分析

这个值就代表的每个线程中
, stack中最多回收的元素的个数

 

继续跟重载的构造方法:


1
2
3
4
1protected Recycler(int maxCapacityPerThread) {
2    this(maxCapacityPerThread, MAX_SHARED_CAPACITY_FACTOR);
3}
4

这里又调用了重载的构造方法
, 并且传入刚才传入的
32768和
MAX_SHARED_CAPACITY_FACTOR

MAX_SHARED_CAPACITY_FACTOR
默认值是
2, 同样在
static块中进行了初始化
, 有关该属性的用处稍后讲解

继续跟构造方法
:


1
2
3
4
1protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor) {
2    this(maxCapacityPerThread, maxSharedCapacityFactor, RATIO, MAX_DELAYED_QUEUES_PER_THREAD);
3}
4

这里同样调用了重载的构造方法
, 传入了刚才
32768和
2, 还有两个属性
RATIO和
MAX_DELAYED_QUEUES_PER_THREAD

RATIO
也在
static中被初始化
, 默认值是
8

同上
, MAX_DELAYED_QUEUES_PER_THREAD的默认值是
2倍
cpu核数

 

我们继续跟构造方法
:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor,
2                   int ratio, int maxDelayedQueuesPerThread) {
3    ratioMask = safeFindNextPositivePowerOfTwo(ratio) - 1;
4    if (maxCapacityPerThread <= 0) {
5        this.maxCapacityPerThread = 0;
6        this.maxSharedCapacityFactor = 1;
7        this.maxDelayedQueuesPerThread = 0;
8    } else {
9        this.maxCapacityPerThread = maxCapacityPerThread;
10        this.maxSharedCapacityFactor = max(1, maxSharedCapacityFactor);
11        this.maxDelayedQueuesPerThread = max(0, maxDelayedQueuesPerThread);
12    }
13}
14

这里将几个属性进行了初始化

首先看
ratioMask, 这里的方法
safeFindNextPositivePowerOfTwo的参数
ratio为
8, 该方法的意思就是大于等于
8的
2的幂次方
-1, 这里就是
ratioMask就是
7

maxCapacityPerThread
是刚才分析的
32768, 是一个大于
0的数
, 所以进入
else

maxCapacityPerThread

32768

maxSharedCapacityFactor
的值为
2

 

maxDelayedQueuesPerThread
的值为
2倍
CPU核数

 

我们再回到
Stack的构造方法中
:


1
2
3
4
5
6
7
8
9
10
11
1Stack(Recycler<T> parent, Thread thread, int maxCapacity, int maxSharedCapacityFactor,
2      int ratioMask, int maxDelayedQueues) {
3    this.parent = parent;
4    this.thread = thread;
5    this.maxCapacity = maxCapacity;
6    availableSharedCapacity = new AtomicInteger(max(maxCapacity / maxSharedCapacityFactor, LINK_CAPACITY));
7    elements = new DefaultHandle[min(INITIAL_CAPACITY, maxCapacity)];
8    this.ratioMask = ratioMask;
9    this.maxDelayedQueues = maxDelayedQueues;
10}
11

根据
Recycler初始化属性的逻辑
, 我们可以知道
Stack中几个属性的值
:

maxCapacity
默认值为
32768

ratioMask
默认值为
7

maxDelayedQueues
默认值是两倍
cpu核数

availableSharedCapacity
的默认值是
32768/2, 也就是
16384

 

以上就是
Recycler创建的相关逻辑

 

上一节: FastThreadLocal的set方法

下一节: recycler中获取对象

 

posted on
2019-01-02 15:40 向南是个万人迷 阅读(
…) 评论(
…) 编辑 收藏

转载于:https://www.cnblogs.com/xiangnan6122/p/10208908.html

给TA打赏
共{{data.count}}人
人已打赏
安全网络

CDN安全市场到2022年价值76.3亿美元

2018-2-1 18:02:50

安全运维

【下一代核心技术DevOps】:(七)持续集成Jenkins的应用(Aliyun Pipiline持续构建)

2021-10-12 11:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索