This article mainly shares the creation process of NioEventLoop thread bound by server socketchannel
In the server startup process, when the registration operation is executed, it will determine whether the current thread is the thread in NioEventLoop bound by ServerSocketChannel. If not, it will encapsulate the registration operation as a thread task and give it to the thread in NioEventLoop for execution. The relevant code is as follows:
@Override public final void register(EventLoop eventLoop, final ChannelPromise promise) { if (eventLoop == null) { throw new NullPointerException("eventLoop"); } if (isRegistered()) { promise.setFailure(new IllegalStateException("registered to an event loop already")); return; } if (!isCompatible(eventLoop)) { promise.setFailure( new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName())); return; } AbstractChannel.this.eventLoop = eventLoop; if (eventLoop.inEventLoop()) { register0(promise); } else {//If the current thread is not the thread in NioEventLoop bound by ServerSocketChannel try { eventLoop.execute(new Runnable() { @Override public void run() { register0(promise); } }); } catch (Throwable t) { logger.warn( "Force-closing a channel whose registration task was not accepted by an event loop: {}", AbstractChannel.this, t); closeForcibly(); closeFuture.setClosed(); safeSetFailure(promise, t); } } }
In the code, the eventLoop.inEventLoop() method will be called to determine whether the current thread is a thread in eventLoop. If not, the eventLoop.execute(Runnable runnable) method will be called to submit the task to eventLoop for execution.
The related logic is implemented in the parent class SingleThreadEventxecutor class:
/** * When executing the registration logic, the current thread is the main thread */ @Override public void execute(Runnable task) { if (task == null) {//Validity verification throw new NullPointerException("task"); } //Whether the current thread is a thread in EventLoop bound by ServerSocketChannel //Current thread is main thread, so inEventLoop should be false boolean inEventLoop = inEventLoop(); addTask(task);//Add thread task to task queue in EventLoop if (!inEventLoop) { startThread();//Startup thread //If the thread has been closed, remove the task submitted to the task queue, and call the rejection policy to reject the execution of the task if (isShutdown() && removeTask(task)) { reject(); } } if (!addTaskWakesUp && wakesUpForTask(task)) { wakeup(inEventLoop); } }
Add a thread task to the thread's task queue
protected void addTask(Runnable task) { if (task == null) { throw new NullPointerException("task"); } if (!offerTask(task)) { reject(task); } }
Create and start threads
Status enumeration of threads
key | value | Meaning |
---|---|---|
ST_NOT_STARTED | 1 | Thread not started |
ST_STARTED | 2 | Thread started |
ST_SHUTTING_DOWN | 3 | Thread shutting down |
ST_SHUTDOWN | 4 | Thread closed |
ST_TERMINATED | 5 | Thread terminated |
//If the thread has not been started, Unsafe is called to modify the corresponding properties of the thread //Call the doStartThread() method to start the thread private void startThread() { if (state == ST_NOT_STARTED) { if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) { try { doStartThread(); } catch (Throwable cause) { STATE_UPDATER.set(this, ST_NOT_STARTED); PlatformDependent.throwException(cause); } } } }
private void doStartThread() { assert thread == null;//Assert that the current thread is empty //Call the execute(Runnable task) method of threadpertask executor to execute the create thread task executor.execute(new Runnable() { @Override public void run() { thread = Thread.currentThread(); if (interrupted) { thread.interrupt(); } boolean success = false; updateLastExecutionTime();//Record execution time try { SingleThreadEventExecutor.this.run(); success = true; } catch (Throwable t) { logger.warn("Unexpected exception from an event executor: ", t); } finally { for (;;) { int oldState = state; if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet( SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) { break; } } // Check if confirmShutdown() was called at the end of the loop. if (success && gracefulShutdownStartTime == 0) { if (logger.isErrorEnabled()) { logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " + SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " + "be called before run() implementation terminates."); } } try { // Run all remaining tasks and shutdown hooks. for (;;) { if (confirmShutdown()) { break; } } } finally { try { cleanup(); } finally { STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED); threadLock.release(); if (!taskQueue.isEmpty()) { if (logger.isWarnEnabled()) { logger.warn("An event executor terminated with " + "non-empty task queue (" + taskQueue.size() + ')'); } } terminationFuture.setSuccess(null); } } } } }); }
ThreadPerTaskExecutor
The threadpertaskexecutior class is as follows
public final class ThreadPerTaskExecutor implements Executor { private final ThreadFactory threadFactory; public ThreadPerTaskExecutor(ThreadFactory threadFactory) { if (threadFactory == null) { throw new NullPointerException("threadFactory"); } this.threadFactory = threadFactory; } @Override public void execute(Runnable command) { threadFactory.newThread(command).start();//Call the NewThread method of thread engineering to create a thread and start it } }
The code of the newThread method of the DefaultThreadFactory Thread factory is as follows, that is, the Thread created through the DefaultThreadFactory Thread factory is the FastThreadLocalThread class, which is an extension of Netty to the JDK native Thread class. The following article analyzes the class in detail, which can be temporarily considered as Thread.
@Override public Thread newThread(Runnable r) { Thread t = newThread(FastThreadLocalRunnable.wrap(r), prefix + nextId.incrementAndGet()); try { if (t.isDaemon() != daemon) {//Set whether the thread is a guardian thread t.setDaemon(daemon); } if (t.getPriority() != priority) {//Set thread priority t.setPriority(priority); } } catch (Exception ignored) { } return t; } protected Thread newThread(Runnable r, String name) { return new FastThreadLocalThread(threadGroup, r, name); }
The relationship among NioEventLoop, SingleThreadEventExecutor and threadpertask executor
The relationships among NioEventLoop, SingleThreadEventExecutor and threadpertask executor are as follows:
The main function of SingleThreadEventExecutor class is to execute thread tasks
The main function of threadpertakexecutior class is to create Netty threads
SingleThreadEventExecutor class is the parent class of NioEventLoop, and threadpertakeexecutor is a member property of SingleThreadEventExecutor, which is initialized by the constructor.
[failed to save the image in the external link. The source station may have anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-haqfcnkv-157951393050) (/ users / lijiaxing / desktop / book / article image to be read / NioEventLoop, SingleThreadEventExecutor and threadpertask executor relationship. png))
eventLoop.execute(Runnable task) —>
SingleThreadEventExecutor.execute(Runnable task)—>
startThread()—>
doStartThread();—>
executor.execute(Runnable task)—>
ThreadPerTaskExecutor.execute(Runnable command)—>
DefaultThreadFactory.newThread(Runnable r)
summary
1. Create a thread when EventLoop performs a thread task, so the thread in the EventLoop of Netty is Lazy create
2. The call chain to create the EventLoop thread is
eventLoop.execute(Runnable task)
—>SingleThreadEventExecutor.execute(Runnable task)
—>startThread()
—>doStartThread()
—>executor.execute(Runnable task)
—>ThreadPerTaskExecutor.execute(Runnable command)
—>DefaultThreadFactory.newThread(Runnable r)