netty 并发数,netty多线程

  netty 并发数,netty多线程

  00-1010获取不同线程释放的对象。在介绍之前,我们先来看看Stack类中的两个属性。我们遵循pop方法,并继续遵循scavengeSome方法。我们继续分析转移方法。那我们就关注一个细节。我们遵循回收空间方法一章的总结。门户:回收不同线程下的对象。

  上一节00-1010分析了不同的线程回收对象,原理是通过与stack关联的WeakOrderQueue来回收。

  如果对象被不同的线程回收,当前线程需要取出对象进行二次利用。如果当前堆栈为空,则通过与当前堆栈关联的WeakOrderQueue取出,这也是要分析得到不同线程释放的对象的小写。

  

目录

private WeakOrderQueue游标,prev私有易失性WeakOrderQueue头;这里是指向WeakOrderQueue的所有指针,我们在上一节中分析过的WeakOrderQueue的head指向与stack关联的新创建的WeakOrderQueue,也就是head节点。

 

  Cursor表示当前weakorderqueue,pre是cursor的上一个节点,如图3360所示。

  8-7-1

  我们从获取对象的入口方法开始分析,获取句柄。

  public final T get(){ if(maxCapacityPerThread==0){ return new object((HandleT)NOOP _ HANDLE);} stack t stack=thread local . get();DefaultHandleT handle=stack . pop();if(handle==null){ handle=stack . new handle();handle . value=new object(handle);} return(T)handle . value;}这个逻辑我们并不陌生。堆栈对象通过pop弹出一个句柄。

  

获取异线程释放对象

DefaultHandleT pop(){ int size=this . size;if (size==0) { if(!scavenge()) {返回null} size=this.size}大小-;default handle ret=elements[size];elements[size]=null;if (ret.lastRecycledId!=ret . recycle id){ throw new IllegalStateException(回收多次);} ret . recycle id=0;ret . lastreecyclid=0;this.size=size返回ret}这里我们重点讲一下,如果size为空,也就是当前tack为空的时候,我们会去找scavenge方法,就是从WeakOrderQueue获取对象的方法。

 

  后续清除方法

  boolean scavenge(){ if(scavensome()){ return true;} prev=null光标=头部;返回false} scavengeSome方法表示对象已经恢复,然后直接返回。如果对象尚未恢复,prev和游标指针将被重置。

  

在介绍之前我们首先看Stack类中的两个属性

布尔清道夫(){ WeakOrderQueue cursor=this . cursor;if(cursor==null){ cursor=head;if (cursor==null) {返回false

 

   } } boolean success = false; WeakOrderQueue prev = this.prev; 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.next = next; } } else { prev = cursor; } cursor = next; } while (cursor != null && !success); this.prev = prev; this.cursor = cursor; return success;}首先拿到cursor指针, cursor指针代表要回收的WeakOrderQueue

  如果cursor为空, 则让其指向头节点, 如果头节点也空, 说明当前stack没有与其关联的WeakOrderQueue, 则返回false

  通过一个布尔值success标记回收状态

  然后拿到pre指针, 也就是cursor的上一个节点, 之后进入一个do-while循环

  do-while循环的终止条件是, 如果没有遍历到最后一个节点并且回收的状态为false, 这里我们可以分析到再循环体里, 是不管遍历与stack关联的WeakOrderQueue, 直到弹出对象为止

  跟到do-while循环中:

  首先cursor指针会调用transfer方法, 该方法表示从当前指针指向的WeakOrderQueue中将元素放入到当前stack中, 如果取出成功则将success设置为true并跳出循环, transfer我们稍后分析, 我们继续往下看

  如果没有获得元素, 则会通过next属性拿到下一个WeakOrderQueue, 然后会进入一个判断if(cursor.owner.get() ==null)

  owner属性我们上一小节提到过, 就是与当前WeakOrderQueue关联的一个线程, get方法就是获得关联的线程对象, 如果这个对象为null说明该线程不存在, 则进入if块, 也就是一些清理的工作

  if块中又进入一个判断if(cursor.hasFinalData()), 这里表示当前的WeakOrderQueue中是否还有数据, 如果有数据则通过for循环将数据通过transfer方法传输到当前stack中, 传输成功的, 将success标记为true

  transfer方法是将WeakOrderQueue中一个link中的handle往stack进行传输, 有关link的相关内容, 我们上一小节也进行过分析

  所以这里通过for循环将每个link的中的数据传输到stack中

  继续往下看, 如果pre节点不为空, 则通过prev.next = next将cursor节点进行释放, 也就是pre的下一个节点指向cursor的下一个节点

  继续往下看else块中的prev = cursor

  这里表示如果当前线程还在, 则将prev赋值为cursor, 代表prev后移一个节点

  最后通过cursor = next将cursor后移一位, 然后再继续进行循环

  循环结束之后, 将stack的prev和cursor属性进行保存

  我们跟到transfer方法中, 分析如何将WeakOrderQueue中的handle传输到stack中:

  

boolean transfer(Stack<?> dst) { Link head = this.head; if (head == null) { return false; } if (head.readIndex == LINK_CAPACITY) { if (head.next == null) { return false; } this.head = head = head.next; } final int srcStart = head.readIndex; int srcEnd = head.get(); final int srcSize = srcEnd - srcStart; if (srcSize == 0) { return false; } final int dstSize = dst.size; final int expectedCapacity = dstSize + srcSize; if (expectedCapacity > dst.elements.length) { final int actualCapacity = dst.increaseCapacity(expectedCapacity); srcEnd = min(srcStart + actualCapacity - dstSize, srcEnd); } if (srcStart != srcEnd) { final DefaultHandle[] srcElems = head.elements; final DefaultHandle[] dstElems = dst.elements; int newDstSize = dstSize; for (int i = srcStart; i < srcEnd; i++) { DefaultHandle element = srcElems[i]; if (element.recycleId == 0) { element.recycleId = element.lastRecycledId; } else if (element.recycleId != element.lastRecycledId) { throw new IllegalStateException("recycled already"); } srcElems[i] = null; if (dst.dropHandle(element)) { continue; } element.stack = dst; dstElems[newDstSize ++] = element; } if (srcEnd == LINK_CAPACITY && head.next != null) { reclaimSpace(LINK_CAPACITY); this.head = head.next; } head.readIndex = srcEnd; if (dst.size == newDstSize) { return false; } dst.size = newDstSize; return true; } else { return false; }}

 

  8-7-2

  我们上一小节分析过, WeakOrderQueue是由多个link组成, 每个link通过链表的方式进行关联, 其中head属性指向第一个link, tail属性指向最后一个link

  在每个link中有多个handle

  在link中维护了一个读指针readIndex, 标记着读取link中handle的位置

  

 

  

我们继续分析transfer方法

首先获取头结点, 并判断头结点是否为空, 如果头结点为空, 说明当前WeakOrderQueue并没有link, 返回false

 

  if(head.readIndex == LINK_CAPACITY)这里判断读指针是否为16, 因为link中元素最大数量就是16, 如果读指针为16, 说明当前link中的数据都被取走了

  接着判断head.next ==null, 表示是否还有下一个link, 如果没有下一个link, 则说明当前WeakOrderQueue没有元素了, 则返回false

  

 

  8-7-3

  继续往下看, 拿到head节点的读指针和head中元素的数量, 接着计算可以传输元素的大小, 如果大小为0, 则返回false

  

 

  8-7-4

  接着, 拿到当前stack的大小, 当前stack大小加上可以传输的大小表示stack中所需要的容量

  if(expectedCapacity > dst.elements.length)表示如果需要的容量大于当前stack中所维护的数组的大小, 则将stack中维护的数组进行扩容, 进入if块中

  扩容之后会返回actualCapacity, 表示扩容之后的大小

  再看srcEnd = min(srcStart + actualCapacity - dstSize, srcEnd)这步

  srcEnd表示可以从Link中取的最后一个元素的下标

  srcStart + actualCapacity - dstSize这里我们进行一个拆分, actualCapacity - dstSize表示扩容后大大小-原stack的大小, 也就是最多能往stack中传输多少元素

  读指针+可以往stack传输的数量, 可以表示往stack中传输的最后一个下标, 这里的下标和srcEnd中取一个较小的值, 也就是既不能超过stack的容量, 也不能造成当前link中下标越界

  继续往下看

  intnewDstSize = dstSize表示初始化stack的下标, 表示stack中从这个下标开始添加数据

  然后判断srcStart != srcEnd, 表示能不能同link中获取内容, 如果不能, 则返回false, 如果可以, 则进入if块中

  接着拿到当前link的数组elements和stack中的数组elements

  然后通过for循环, 通过数组下标的方式不断的将当前link中的数据放入到stack中

  for循环中首先拿到link的第i个元素

  

 

  

接着我们我们关注一个细节

if (element.recycleId == 0) { element.recycleId = element.lastRecycledId;} else if (element.recycleId != element.lastRecycledId) { throw new IllegalStateException("recycled already");}

这里element.recycleId == 0表示对象没有被回收过, 如果没有被回收过, 则赋值为lastRecycledId, 我们前面分析过lastRecycledId是WeakOrderQueue中的唯一下标, 通过赋值标记element被回收过

 

  然后继续判断element.recycleId != element.lastRecycledId, 这表示该对象被回收过, 但是回收的recycleId却不是最后一次回收lastRecycledId, 这是一种异常情况, 表示一个对象在不同的地方被回收过两次, 这种情况则抛出异常

  接着将link的第i个元素设置为null

  继续往下看:

  

if (dst.dropHandle(element)) { continue;}

这里表示控制回收站回收的频率, 之前的小节我们分析过, 这里不再赘述

 

  element.stack = dst表示将handle的stack属性设置到当前stack

  dstElems[newDstSize ++] = element这里通过数组的下标的方式将link中的handle赋值到stack的数组中

  继续往下看:

  

if (srcEnd == LINK_CAPACITY && head.next != null) { reclaimSpace(LINK_CAPACITY); this.head = head.next;}

这里的if表循环结束后, 如果link中的数据已经回收完毕, 并且还有下一个节点则会进到reclaimSpace方法

 

  

 

  

我们跟到reclaimSpace方法

private void reclaimSpace(int space) { assert space >= 0; availableSharedCapacity.addAndGet(space);}

这里将availableSharedCapacity加上16, 表示WeakOrderQueue还可以继续插入link

 

  继续看transfer方法

  

this.head = head.next表示将head节点后移一个元素

 

  head.readIndex = srcEnd表示将读指针指向srcEnd, 下一次读取可以从srcEnd开始

  if(dst.size == newDstSize)表示没有向stack传输任何对象, 则返回false

  

否则就通过dst.size = newDstSize更新stack的大小为newDstSize, 并返回true

 

  以上就是从link中往stack中传输数据的过程

  

 

  

章节小结

这一章主要讲解了两个性能优化工具了FastThreadLocal和Recycler

 

   FastThreadLocal和jdk的ThreadLocal功能类似, 只是性能更快, 通过FastTreadLocalThread中的threadLocalMap对象, 通过数组下标的方式进行保存和获取对象

   Recycler是一个轻量级的对象回收站, 用于对象重用, 避免了对象的频繁创建和减轻gc的压力

   Recycler同线程回收对象是通过一个线程共享的stack实现的, 将对象包装成handle并存入stack中

   Reclyer异线程回收对象是将handle存入一个与stack关联的WeakOrderQueue中, 同一个stack中关联的不同WeakOrderQueue由不同的线程创建

   从Recycler获取对象时stack中有值, 则可以直接从stack中获取

   如果stack中没有值则通过stack关联的WeakOrderQueue中获取

  以上就是Netty分布式获取异线程释放对象源码剖析的详细内容,更多关于Netty分布式获取异线程释放对象的资料请关注盛行IT其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: