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

第五节: 同线程回收对象

上一小节剖析了从recycler中获取一个对象, 这一小节分析在创建和回收是同线程的前提下, recycler是如何进行回收的

回顾第三小节的demo中的main方法:

public static void main(String[] args){
User user1 = RECYCLER.get();
user1.recycle();
User user2 = RECYCLER.get();
user2.recycle();
System.out.println(user1==user2);
}

这里就是一个同线程回收对象的典型场景, 在一个线程中将对象创建并且回收, 我们的User对象定义了recycle方法

static class User{
private final Recycler.Handle<User> handle;
public User(Recycler.Handle<User> handle){
this.handle=handle;
}
public void recycle(){
handle.recycle(this);
}
}

这里的recycle是通过handle对象的recycle方法实现对象回收的, 这里实际调用的是DefaultHandle的recycle方法

我们跟进recycle方法:

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

这里如果回收的对象为null, 则抛出异常

如果不为null, 则通过自身绑定stack的push方法将自身push到stack中

跟到push方法中:

void push(DefaultHandle<?> item) {
Thread currentThread = Thread.currentThread();
if (thread == currentThread) {
pushNow(item);
} else {
pushLater(item, currentThread);
}
}

这里首先判断当前线程, 和创建stack的时候保存的线程是否是同一线程, 如果是, 说明是同线程回收对象, 则执行pushNow方法将对象放入stack中

跟到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)) {
return;
}
if (size == elements.length) {
elements = Arrays.copyOf(elements, min(size << 1, maxCapacity));
}
elements[size] = item;
this.size = size + 1;
}

如果第一次回收, item.recycleId和item.lastRecycledId都为0, 所以不会进入if块, 我们继续往下看

item.recycleId = item.lastRecycledId = OWN_THREAD_ID 这一步将handle的recycleId和lastRecycledId赋值为OWN_THREAD_ID, OWN_THREAD_ID在每一个recycle中是唯一固定的, 这里我们只需要记得这个概念就行

然后获取当前size

如果size超过上限大小, 则直接返回

这里还有个判断dropHandle, 我们跟进去:

boolean dropHandle(DefaultHandle<?> handle) {
if (!handle.hasBeenRecycled) {
if ((++handleRecycleCount & ratioMask) != 0) {
return true;
}
handle.hasBeenRecycled = true;
}
return false;
}

if (!handle.hasBeenRecycled) 表示当前对象之前是否没有被回收过, 如果是第一次回收, 这里会返回true, 然后进入放到if

再看if中的判断 if ((++handleRecycleCount & ratioMask) != 0)

handleRecycleCount表示当前位置stack回收了多少次对象(回收了多少次, 不代表回收了多少个对象, 因为不是每次回收都会被成功的保存在stack), ratioMask我们之前分析过是7, 这里 (++handleRecycleCount & ratioMask) != 0 表示回收的对象数如果不是8的倍数, 则返回true, 表示只回收1/8的对象

然后将hasBeenRecycled设置为true, 表示已经被回收

回到pushNow方法中:

如果size的大小等于stack中的数组elements的大小, 则将数组elements进行扩容

最后将size通过数组下标的方式将当前handle设置到elements的元素中, 并将size进行自增

以上就是同线程回收对象的逻辑

上一节: reclycer中获取对象

下一节: 异线程回收对象

Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)---->第5节: 同线程回收对象的更多相关文章

  1. Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)---->第6节: 异线程回收对象

    Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler 第六节: 异线程回收对象 异线程回收对象, 就是创建对象和回收对象不在同一条线程的情况下, 对象回收的逻辑 我 ...

  2. Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)---->第7节: 获取异线程释放的对象

    Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler 第七节: 获取异线程释放的对象 上一小节分析了异线程回收对象, 原理是通过与stack关联的WeakOrder ...

  3. Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)---->第4节: recycler中获取对象

    Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler 第四节: recycler中获取对象 这一小节剖析如何从对象回收站中获取对象: 我们回顾上一小节demo的ma ...

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

    Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler 概述: FastThreadLocal我们在剖析堆外内存分配的时候简单介绍过, 它类似于JDK的ThreadL ...

  5. Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)---->第2节: FastThreadLocal的set方法

    Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler 第二节: FastThreadLocal的set方法 上一小节我们学习了FastThreadLocal的创建和 ...

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

    Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler 第三节: recycler的使用和创建   这一小节开始学习recycler相关的知识, recycler是n ...

  7. Netty源码分析第3章(客户端接入流程)---->第1节: 初始化NioSockectChannelConfig

    Netty源码分析第三章: 客户端接入流程 概述: 之前的章节学习了server启动以及eventLoop相关的逻辑, eventLoop轮询到客户端接入事件之后是如何处理的?这一章我们循序渐进, 带 ...

  8. Netty源码分析第3章(客户端接入流程)---->第2节: 处理接入事件之handle的创建

    Netty源码分析第三章: 客户端接入流程 第二节: 处理接入事件之handle的创建 上一小节我们剖析完成了与channel绑定的ChannelConfig初始化相关的流程, 这一小节继续剖析客户端 ...

  9. Netty源码分析第3章(客户端接入流程)---->第3节: NioSocketChannel的创建

    Netty源码分析第三章: 客户端接入流程 第三节: NioSocketChannel的创建 回到上一小节的read()方法: public void read() { //必须是NioEventLo ...

随机推荐

  1. 1.1 What Is This Book About(这本书是关于什么的)

    CHAPTER 1 Preliminaries(预备知识) 1.1 What Is This Book About?(这本书是关于什么的) 这本书关心的是如何用Python对数据进行处理和清洗等操作. ...

  2. Odoo作为后端时如何返回数据给webapp、移动端app

    转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/9307315.html  使用jinja2渲染的页面,可以直接在调用template.render()时传递参数 ...

  3. 详解Tensorflow数据读取有三种方式(next_batch)

    转自:https://blog.csdn.net/lujiandong1/article/details/53376802 Tensorflow数据读取有三种方式: Preloaded data: 预 ...

  4. C#版谷歌地图下载器设计与实现

    关于如何将地球经纬度坐标系统转换成程序中常用到的平面2D坐标系统,网上的文章很多,参考http://www.cnblogs.com/beniao/archive/2010/04/18/1714544. ...

  5. gulp插件 run-sequence(同步执行任务)

    功能描述 gulp默认使用最大并发数执行任务,也就是说所有的任务几乎都是同时执行,而不会等待其它任务.但很多时候,任务是需要有先后次序的,比如要先清理目标目录,然后再执行打包. run-sequenc ...

  6. Jmeter之集合点与关联

    在Jmeter中,实现类似于LoadRunner中集合点的方法是采用同步定时器(Synchronizing Timer),而实现类似于LoadRunner中关联的方法是采用正则表达式提取器. 一.集合 ...

  7. sed 替换有单引号的行

    cat test.txt $config['useragent'] = 'Roundcube Webmail'; // Hide version number//$config['username_d ...

  8. 前端获取table表格里面的所有(单个)tr和所有(单个)td,用js实现

    今天在做项目遇到了一个问题,就是获取不到table里面的td. 本来是打算使用jq来解决的,但网上大部分人使用的都是获取到table标签然后点出他的children函数,我的前端页面没有这个函数,然后 ...

  9. MySQL基础----py全栈

    目录 MySQL基础----py全栈 一.引言 1.什么是数据? 2.什么是数据库(DB)? 3.什么是数据库管理系统(DBMS)? 4.什么是数据库系统? 5.数据库管理系统由来 6.什么是数据模型 ...

  10. Vue.js下载方式及基本概念

    Vue.js 简介 说明及下载 Vue.js使用文档已经写的很完备和详细了,通过以下地址可以查看: https://cn.vuejs.org/v2/guide/ vue.js如果当成一个库来使用,可以 ...