Inheritance Relationship:
Initialization of Nioeventloop
Nioeventloop (nioeventloopgroup parent, Threadfactory threadfactory, Selectorprovider selectorprovider) {
super ( Parent, threadfactory, false);
if (Selectorprovider = = null) {
throw new NullPointerException ("Selectorprovider");
}
Provider = Selectorprovider;
selector = Openselector ();
}
1, call the parent class method constructs a taskqueue, it is a linkedblockingqueue
2,openselector (): Netty is based on NIO to achieve, so also inseparable from selector.
3,disable_keyset_optimization: to determine whether the need for Sun.nio.ch.SelectorImpl in the Selectedkeys to optimize, do not configure the default need to optimize.
4, where is the main optimization: Netty The Selectedkeyset with the two field in Sun.nio.ch.SelectorImpl by reflection Selectedkeys and Publicselectedkeys bindings, you know Selectorimpl the original selectedkeys and Publicselectedkeys data structures are hashset, and HashSet's data structure is the array + linked list, the new data structure is composed of 2 arrays A, B, the initial size is 1024, avoid the performance problems caused by hashset expansion. In addition to the expansion, traversal efficiency is also a reason, for the need to traverse all elements of selectedkeys, the efficiency of the array is undoubtedly the highest.
Private Selector Openselector () {final Selector Selector;
try {selector = Provider.openselector ();
catch (IOException e) {throw new Channelexception ("Failed to open a new selector", e);
} if (disable_keyset_optimization) {return selector;
try {selectedselectionkeyset selectedkeyset = new Selectedselectionkeyset (); class<?> Selectorimplclass = Class.forName ("Sun.nio.ch.SelectorImpl", False, Platformdependent.getsy
Stemclassloader ());
Ensure the current selector implementation is what we can instrument.
if (!selectorimplclass.isassignablefrom (Selector.getclass ())) {return selector;
Field Selectedkeysfield = Selectorimplclass.getdeclaredfield ("Selectedkeys");
Field Publicselectedkeysfield = Selectorimplclass.getdeclaredfield ("Publicselectedkeys");
Selectedkeysfield.setaccessible (TRUE); Publicselectedkeysfield.setaCcessible (TRUE);
Selectedkeysfield.set (selector, selectedkeyset);
Publicselectedkeysfield.set (selector, selectedkeyset);
Selectedkeys = Selectedkeyset;
Logger.trace ("instrumented a optimized Java.util.Set into: {}", selector);
catch (Throwable t) {selectedkeys = null;
Logger.trace ("Failed to instrument a optimized java.util.Set into: {}", selector, T);
return selector; }
start of the Nioeventloop
In the last time, Nioeventloop maintains a thread that invokes the Nioeventloop run method when the thread starts, and the loop loops through a process: Select-> processselectedkeys (IO Task)-> Runalltasks (non-IO Task)
I/O tasks: ready events in Selectionkey, such as accept, connect, read, write, etc.
Non-IO tasks: tasks added to Taskqueue, such as bind, channelactive, etc.
@Override protected void Run () {for (;;)
{Boolean oldwakenup = Wakenup.getandset (false);
try {//To determine if there is a non-IO task, if there is any immediate return if (Hastasks ()) {Selectnow ();
else {select (Oldwakenup);
if (Wakenup.get ()) {selector.wakeup ();
} cancelledkeys = 0;
Needstoselectagain = false;
Final int ioratio = This.ioratio;
if (Ioratio = =) {//IO task Processselectedkeys ();
Non-IO task runalltasks ();
else {//the elapsed time to control the IO task and the non-IO task is longer than the final long iostarttime = System.nanotime ();
Io task Processselectedkeys ();
Final Long iotime = System.nanotime ()-iostarttime;
Non-IO task runalltasks (iotime * (100-ioratio)/ioratio); } if (Isshuttingdown ()) {CloseAll ();
if (Confirmshutdown ()) {break; (Throwable t) {//Prevent possible consecutive immediate failures ' lead T
O//excessive CPU consumption.
try {thread.sleep (1000);
catch (Interruptedexception e) {//Ignore. }
}
}
}
1.wakenup: used to decide whether to call Selector.wakeup (), only if Wakenup is not true, to reduce wake-up load because selector.wakeup () is an expensive operation.
2,hastask (): to determine whether there is a non-IO task, if any, choose to call Non-blocking Selectnow () Let select immediately return, otherwise the blocking way to call Select.timeoutmillis is blocked time
3,ioratio: Control the execution time of two tasks, you can limit the execution time of the non-IO task, the default value is 50, to allow the non-IO task to obtain and IO task the same execution time, this value according to their specific scenario to set.
4,Processselectedkeys (): Handling IO Events
5,runalltasks (): processing non-IO tasks
6,Isshuttingdown (): Check whether the state is marked as St_shutting_down
private void Select (Boolean oldwakenup) throws IOException {Selector Selector = this.selector;
try {int selectcnt = 0;
Long Currenttimenanos = System.nanotime ();
Long Selectdeadlinenanos = Currenttimenanos + Delaynanos (Currenttimenanos); for (;;)
{Long Timeoutmillis = (Selectdeadlinenanos-currenttimenanos + 500000L)/1000000L;
if (timeoutmillis <= 0) {if (selectcnt = = 0) {selector.selectnow ();
selectcnt = 1;
} break;
int selectedkeys = Selector.select (Timeoutmillis);
Selectcnt + +; if (selectedkeys!= 0 | | oldwakenup | | wakenup.get () | | hastasks () | | hasscheduledtasks ()) {//-Sele CTED something,//-Waken up by user, or//-the task queue has a PEnding task.
-A scheduled task is ready to processing break; } if (thread.interrupted ()) {//Thread is interrupted so reset selected keys and BRE
AK so we don't run into a busy loop. As is most likely a bug in the handler of the user or it ' s client library we'll//also log
It. https://github.com/netty/netty/issues/2426 if (logger.isdebugenabled ())
{Logger.debug ("selector.select () returned prematurely because" + "Thread.CurrentThread (). Interrupt () was called.
Use "+" nioeventloop.shutdowngracefully () to shutdown the Nioeventloop. ");
} selectcnt = 1;
Break
Long time = System.nanotime (); if (Time-timeunit.milliseconds.tonanos (timeoutmillis) >= Currenttimenanos) {//Timeo
Utmillis elapsed without anything selected.
selectcnt = 1; else if (Selector_auto_rebuild_threshold > 0 && selectcnt >= selector_auto_rebuild
_threshold) {//The selector returned prematurely many times in a row.
Rebuild the selector to work around the problem. Logger.warn ("Selector.select () returned prematurely {} times in a row;
Rebuilding selector. ", selectcnt);
Rebuildselector ();
selector = This.selector;
Select again to populate Selectedkeys.
Selector.selectnow ();
selectcnt = 1;
Break
} Currenttimenanos = time; } if (Selectcnt > Min_premature_selector_returns) {if (logger.isdebugenabled ()
{Logger.debug ("selector.select () returned prematurely {} times in a row.", selectCnt-1);
The catch (Cancelledkeyexception e) {if (logger.isdebugenabled ()) {
Logger.debug (CancelledKeyException.class.getSimpleName () + "raised by a selector-jdk bug?", e); }
}
}
Protected long Delaynanos (long Currenttimenanos) {
scheduledfuturetask<?> scheduledtask = Peekscheduledtask ();
if (Scheduledtask = = null) {return
schedule_purge_interval;
}
Return Scheduledtask.delaynanos (Currenttimenanos);
}
Public long Delaynanos (long Currenttimenanos) {return
Math.max (0, Deadlinenanos ()-(Currenttimenanos-start_time) );
}
Public long Deadlinenanos () {return
Deadlinenanos;
}
1,Delaynanos (Currenttimenanos): in the parent class Singlethreadeventexecutor has a delay in the execution of the task queue, Delaynanos is going to this delay queue to see if a non-IO task is not performed
* If not, return for 1 seconds.
* If there is a task in the delay queue and the resulting calculated time (Selectdeadlinenanos-currenttimenanos) is less than 500000L nanoseconds, call Selectnow () to return directly, and vice versa to execute a blocked select
2. Select will return immediately if you encounter the following conditions
if (selectedkeys!= 0 | | oldwakenup | | wakenup.get () | | hastasks () | | hasscheduledtasks ()) {
//-Selected something,< c1/>//-Waken up by user, or
//-The task queue has a pending task.
-A scheduled task is ready to processing break
;
Selected something if Select to a Ready connection (Selectedkeys > 0) waken up by user wakes the task queue has a pending task. The task queue came up with a new Tasks a scheduled task is ready for processing delay queue There is an appointment task that needs to be executed at expiration
3.selectcnt: record Select idling times (SELECTCNT), which solves the cpu100% bug caused by the notorious selector Select method in NiO, when the number of idling times exceeds 512 (defines a threshold , this threshold is 512 and can be passed in by setting system Properties Io.netty.selectorAutoRebuildThreshold in the application layer, Netty will reconstruct the new selector, The old selector on the channel transferred to the new selector, close the old selector, replace the old selector with the new selector. See the following Rebuildselector () method in detail
4,rebuildselector (): is above said.
public void Rebuildselector () {if (!ineventloop ()) {Execute (new Runnable () {@Override
public void Run () {rebuildselector ();
}
});
Return
Final Selector oldselector = Selector;
Final Selector Newselector;
if (Oldselector = = null) {return;
try {newselector = Openselector ();
catch (Exception e) {Logger.warn ("Failed to create a new Selector.", e);
Return
}//Register all channels to the new Selector.
int nchannels = 0; for (;;)
{try {for (Selectionkey Key:oldSelector.keys ()) {Object a = key.attachment ();
try {if (!key.isvalid () | | Key.channel (). Keyfor (newselector)!= null) {
Continue
int interestops = Key.interestops ();
Key.cancel (); SElectionkey NewKey = Key.channel (). Register (Newselector, Interestops, a); if (a instanceof Abstractniochannel) {//Update Selectionkey (Abstractni
Ochannel) a). Selectionkey = NewKey;
} nchannels + +;
catch (Exception e) {Logger.warn ("Failed to re-register a Channel to the new Selector.", e); if (a instanceof abstractniochannel) {Abstractniochannel ch = (Abstractniochannel)
A
Ch.unsafe (). Close (Ch.unsafe (). Voidpromise ()); else {@SuppressWarnings ("unchecked") niotask<selectablechannel> t
Ask = (niotask<selectablechannel>) A;
Invokechannelunregistered (Task, key, E);
catch (Concurrentmodificationexception e) { Probably due to concurrent modification of the key set.
Continue
} break;
} selector = Newselector; try {//selector as everything else is registered to the new one oldselector.close (
); The catch (Throwable t) {if (logger.iswarnenabled ()) {Logger.warn ("Failed to close") {"Selector."
, t); } logger.info ("migrated" + Nchannels + "channel (s) to the new Selector.");}
Author: Little Donkey, a game man
Dream: World Peace
GitHub Home: https://liulongling.github.io/
Csdn Home: http://blog.csdn.net/ Liulongling
If there is a mistake, please forgive and welcome the criticism.
This blog does not indicate reproduced articles to the author of all the Small donkey, welcomed the reprint, but without the consent of the author must retain this paragraph of the statement, and in the article page obvious location to the original connection, otherwise retain the right to pursue legal responsibility.