Recycler Analysis
Call Source: Pooledbytebuf.java
The knowledge involved:
- Atomicinteger
- WeakReference
- ThreadLocal
The recycle called in Defaulthandle just puts the objects that need to be recycled in a stack, so the problem turns into how the stack is recycled.
Static Final classDefaulthandle<t>Implementshandle<t> {Private intLastrecycledid;Private intRecycleid;Booleanhasbeenrecycled;PrivateStack<?> Stack;PrivateObject value;Defaulthandle(stack<?> Stack) { This.Stack= Stack; }the initial entry for the//other method call @Override Public void Recycle(Object object) {if(Object! = value) {Throw NewIllegalArgumentException ("Object does not belong to handle"); } stack.Push( This); } }
Then the method of recycling should be related to stack.
***
Before the introduction of the stack to understand the next weakorderqueue, as the name implies, it is a weak ordered queue.
Weakorderqueue is implemented by a linked list, where the stored data is an array of type Defaulthanle. It is important to note that although the class name is a weak reference typeface, there is no weak reference field in the property.
All construction methods in this class are private types, and getting instances can only be obtained through the Newqueue method:
Private Weakorderqueue(stack<?> Stack, thread thread) {head = Tail =New Link(); Owner =NewWeakreference<thread> (Thread);//Its important, we not store the stack itself in the Weakorderqueue as the stack also are used in //The Weakhashmap as key. So just store the enclosed atomicinteger which should allow //Stack itself GCed.availablesharedcapacity = stack.availablesharedcapacity;}StaticWeakorderqueueNewqueue(stack<?> Stack, thread thread) {Weakorderqueue queue =New Weakorderqueue(Stack, thread);//done outside of the constructor to ensure Weakorderqueue.this does not escape the constructor and so //may be accessed and its still constructed.Stack.Sethead(queue);returnQueue }
You can see that the method, in addition to constructing and returning the Weakorderqueue real exception, also puts the instance into a container in a stack instance.
The container's properties in the class are head, and the data structure is the stack implemented with the linked list. Reason
Where Weakorderqueue contains a link inner class that inherits Atomicinteger and contains an array property that holds the Defaulthandle type. The inherited Atomicinteger is used to record the subscript of an array. Code:
privatestaticfinalclassextends AtomicInteger { privatefinalnew DefaultHandle[LINK_CAPACITY]; privateint readIndex; private Link next; }
The role of link, I think, is the basic unit of space allocation and release, and when a link element fills up, a link instance needs to be regenerated and placed at the end of the list. Released when freed in the transfer method.
The role of the transfer method: When a stack has no elements to provide to the consumer, the transfer method transmits the elements in the Weakorderqueue to the stack. The behavior is initiated by the stack, So there is a weakorderqueue linked list in the stack, in which the stack gets the data that the consumer needs. And when a link is fully converted, its references are revoked, waiting for the GC
The elements stored in the stack are instances of the Defaulthandle type, and a head attribute holds the Weakorderqueue.
The stack is the only handle element stored in the Recycler class that is accessible to the outside world. When an instance of itself is insufficient, the transfer method is actively initiated from the Weakorderqueue. The code for the consumer acquisition element is as follows:
//Class recycler Public FinalTGet() {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; }//internal class stackDefaulthandle<t>Pop() {intSize = 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 NewIllegalStateException ("Recycled multiple times"); } ret.Recycleid=0; BEI Ret.Lastrecycledid=0; This.size= size;returnRET;}
which
- If there are no instances in the pool that the stack refers to, a new object is returned.
- Threadlocal solves the problem of thread synchronization, but Netty does not use the JDK comes with the threadlocal, but its own definition of a class called fastthreadlocal implementation, interested can look at the source code.
- Each successful pop instance will have its Recycleid and Lastrecycledid set to 0, ensuring that it can be recycled again.
Notice the meaning of this line of code
if (ret.lastRecycledId != ret.recycleId) { thrownew IllegalStateException("recycled multiple times");}
I think this is true: the instance that stack returns to the consumer is necessarily an instance that no other consumer is using, which means that instances in the stack are not used by other consumers. And when the two values are not equal, if an instance itself is in the stack and has been recycled, When recycled in this state, two values are unequal. Why avoid this situation, because the reference to the same instance will be placed in the stack or in the two position of the Weakorderqueue, when a consumer takes a reference, The other reference is pointing to an instance that is no longer in compliance with the ' nobody uses ' rule, so avoid this situation.
Stack's push method: Pushnow and Pushlater
void push (defaulthandle<?> Item) {Thread CurrentThread = Thread. (); if (Threadref. get () = = CurrentThread) {//the current thread was the thread that belongs to the Stack, we C An-try-to-push the object now. pushnow (item); } else {//the current Thread isn't the one that belongs to the Stack //(or the Thread that belonged to the Stack is collected already), we need To signal that the push //happens later. pushlater (item, CurrentThread); } }
Simply put, the pushnow is placed in the list of elements of the stack, and the pushlater is placed in the list of elements in Weakorderqueue.
Where to store depends on whether the thread reference in the stack is the same as the current thread. So here's a priority, and the stack tends to give itself the available elements of the referencing thread.
Take a look at the online picture to summarize:
- The consumer calls Recyler's Get method, which calls the stack's Pop method to get the element in the pool
- If there are not enough elements in the stack, call the transfer method, trigger the scavenge method, and then get the element from the Weakorderqueue in link. Put it in the stack.
- Call handle's Recycle method to recycle, that is, call the stack's push method to place the recycled element in the appropriate location. Recycler has a recycle method, but has been @deprecated.
The source code analysis of Netty recycler