@Author: zxw
@Email: 502513206@qq.com
1.java thread life cycle
People who know java threads should know that java threads have the following five states
public enum State { // The state when the thread is created, and the thread has not been created in the operating system at this time NEW, // The thread is ready or runnable RUNNABLE, // When resources are occupied, for example, synchronized fails to acquire locks and enters the blocking state BLOCKED, // Call wait(), join() WAITING, // Timeout wait TIMED_WAITING, // End of thread running TERMINATED; }
Here is a reference to the thread state transition diagram of the official account of the big guy.
Official account of image source: low concurrent programming @link:[https://mp.weixin.qq.com/s/6kAMFCXT46mWfxRdega1vA ]
The above just helps us review the thread state in java and the transformation of thread state
2. Threads in netty
We know that netty is implemented based on the master-slave reactor mode, and the asynchrony is realized through the thread group of netty. That is, EventLoopGroup, and group is only the management of thread group. The specific thread execution logic is executed by EventExecutor class. The event executor netty also defines its own cycle, as follows
SingleThreadEventExecutor
private static final int ST_NOT_STARTED = 1; private static final int ST_STARTED = 2; private static final int ST_SHUTTING_DOWN = 3; private static final int ST_SHUTDOWN = 4; private static final int ST_TERMINATED = 5;
Next, let's take a look at how to manage thread groups in netty. We find such a line in the source code. We can see that when creating the EventExecutor class, the default state is 1.
private volatile int state = ST_NOT_STARTED;
Want to start from not_ If the start state changes to the start state, it will change only when it is started. Through the source code, the following methods are found in the startup. According to the method name, this is the method to start the internal thread of netty. In this method, the thread's not_ The start status is set to start
private void startThread() { if (state == ST_NOT_STARTED) { if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) { boolean success = false; try { doStartThread(); success = true; } finally { if (!success) { STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED); } } } } }
The status of the EventExecutor is as follows
When the thread starts, netty will loop out data from its queue and execute. If there is no data, it will enter the blocking state. Therefore, the state in the EventExecutor will change only when we call the method manually.
netty provides two methods to put the EventExecutor into the shutdown state.
- Shutdown gracefully: graceful shutdown
- Shutdown: shutdown
For the first graceful shutdown, the processing in netty is if the current state of EventExecutor is still no_start status, the EventExecutor will be started, which can be realized by the following methods
private boolean ensureThreadStarted(int oldState) { if (oldState == ST_NOT_STARTED) { try { doStartThread(); } catch (Throwable cause) { STATE_UPDATER.set(this, ST_TERMINATED); terminationFuture.tryFailure(cause); if (!(cause instanceof Exception)) { // Also rethrow as it may be an OOME for example PlatformDependent.throwException(cause); } return true; } } return false; }
Now let's sort out the flow chart
So there's only one last state left_ Terminated. After looking at the above code, we find that there is such a line of state in catch_ UPDATER. set(this, ST_TERMINATED);, You can see that if the current thread executes abnormally, netty will directly set the status of EventExecutor to St_ Terminated, here is one of the reasons why the execution status changes to closed. If there is no exception during normal execution, it should be the end of our program, and the state will naturally change to St_ Terminated.
In netty, the status will be changed in the finally block in the subsequent logic after the thread is executed
try { cleanup(); } finally { FastThreadLocal.removeAll(); STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED); threadLock.countDown(); int numUserTasks = drainTasks(); if (numUserTasks > 0 && logger.isWarnEnabled()) { logger.warn("An event executor terminated with " + "non-empty task queue (" + numUserTasks + ')'); } terminationFuture.setSuccess(null); }
Now the life cycle of netty's EventExecutor is as follows, although what is similar to java thread, there is no correlation between the two. Netty puts all tasks into the task queue, takes out Runnable from the queue, and then calls run method.
In fact, for normal tasks, the flow order is a sequence, as follows