Author: small Fu Ge blog: https://bugstack.cn Github:https://github.com/fuzhengwei/CodeGuide/wiki
Precipitation, share, grow, let yourself and others can gain something! 😄
One, foreword
There is a saying: because you are excellent, so it is difficult to excellence!
When I first heard this sentence, I was still in school. It was neither excellent nor excellent, and maybe even a little stupid! But suddenly from some time to climb to the top of the class after a few, began to like this feeling, the original front of the scenery is so brilliant 😜!
The difference between excellence and excellence is not a grade, when you feel excellent, but also to keep the empty bottle mentality, can gradually like excellence, and long!
It’s easier to learn more when you’re young, but the older you get, the dumber you get! People can easily be taken for older by their age. But rarely can maintain a low profile humble mentality, continuous learning. So finally, can not put their own, also can not pick up the ability.
Like a sentence, blue is the color of the sky, red is the symbol of fire, I do not copy the blue of the sea, nor do I imitate the red of fire sunset. I am me, life is mine, fate is mine. Fitness is also yours, learning is also yours, as long as you have a good attitude, naturally will go to the front of excellence there!
2. Interview questions
Thanks for the plane, note! Chad, young people write code like crazy, don’t follow the rules and yell at me! You want rattail juice! Thank the plane scolding after work, looking for an interviewer to talk about experience.
Thank plane: I feel every day like live in the dunghill, code is chaotic, I have heart powerless!
Interviewer: What, want to change jobs?
Thank plane: want to write code have standard company, want to promote!
Interviewer: HMM! It’s true that some big companies have better code quality. But you also need to be strong on your own.
Xie Plane: Yes, I’ve been studying hard! Get ready to run!
Interviewer: Let me give you a quiz to see how likely you are to enter a big factory. B: well… How do Java threads start?
Thank plane: how to start? Start start!
Interviewer: Anything else?
Xie Plane: HMM… , no!
Interviewer: Well, it may or may not tell you how great your code is, but the depth and breadth of your technical stack will determine whether or not you’ll have a successful programming career. Still have to work hard!
Three, thread start analysis
new Thread(() -> {
// todo
}).start();
Copy the code
Ahem, Java thread creation and startup is pretty simple, but it’s often not clear how a thread is started, or even why it is started by calling start() instead of the run() method.
So, just to give you a little bit of intuition, let’s start with the perspective of God. This section of Java thread code, to JDK method use, as well as the corresponding processing process of the JVM, to show you, to facilitate our subsequent step by step analysis.
The above is the analysis of the whole process of starting a thread, which involves the following knowledge points:
- Starting a thread involves a call to a local method (JNI), that part of the code written in C++.
- JVM implementations will have unified handling of threads for different operating systems, such as Win, Linux, and Unix.
- Starting a thread involves the thread’s RUNNABLE state, as well as the wake up operation, so eventually there will be a callback.That’s calling our run() method
Next, we will begin to analyze the execution of each step of the source code to understand the thread start process.
The thread startup process
1. Thread Start UML diagram
Figure 19-2 shows the timing sequence diagram of the thread startup process. The overall link is long and involves the operation of JVM. The core source code is as follows:
Thread.c
:Github.com/unofficial-…jvm.cpp
:Github.com/JetBrains/j…thread.cpp
:Github.com/JetBrains/j…os.cpp
:Github.com/JetBrains/j…os_linux.cpp
:Github.com/JetBrains/j…os_windows.cpp
:Github.com/JetBrains/j…vmSymbols.hpp
:Github.com/JetBrains/j…
2. Start Thread on the Java layer
2.1 the start () method
new Thread(() -> {
// todo
}).start();
/ / the JDK source code
public synchronized void start(a) {
if(threadStatus ! =0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if(! started) { group.threadStartFailed(this); }}catch (Throwable ignore) {}
}
}
Copy the code
- Thread start method
start()
The core content is described in its method English annotations.Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.
The JVM calls the thread’s run method, causing it to start executing.This is actually a CALLBACK process for the JVM, as described in the source code analysis below - In addition
start()
Is asynchronized
Method, but to avoid multiple calls, is determined by thread state in the method.threadStatus ! = 0
. group.add(this)
Add the current thread to a ThreadGroup.start0()
, is a local method that is invoked by JNI. This step is the core step of starting the thread.
2.2 start0() Local method
// The local method start0
private native void start0(a);
// Register local methods
public class Thread implements Runnable {
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives(a);
static {
registerNatives();
}
// ...
}
Copy the code
start0()
Is a local method used to start a thread.registerNatives()
This method is used to register local methods that are needed during thread execution, such as:start0
,isAlive
,yield
,sleep
,interrupt0
And so on.
RegisterNatives, the local method is defined in Thread.c, and the following is the core source of the definition:
static JNINativeMethod methods[] = {
{"start0"."()V", (void *)&JVM_StartThread},
{"stop0"."(" OBJ ")V", (void *)&JVM_StopThread},
{"isAlive"."()Z", (void *)&JVM_IsThreadAlive},
{"suspend0"."()V", (void *)&JVM_SuspendThread},
{"resume0"."()V", (void *)&JVM_ResumeThread},
{"setPriority0"."(I)V", (void *)&JVM_SetThreadPriority},
{"yield"."()V", (void *)&JVM_Yield},
{"sleep"."(J)V", (void *)&JVM_Sleep},
{"currentThread"."()" THD, (void *)&JVM_CurrentThread},
{"interrupt0"."()V", (void *)&JVM_Interrupt},
{"holdsLock"."(" OBJ ")Z", (void *)&JVM_HoldsLock},
{"getThreads"."()" THD, (void *)&JVM_GetAllThreads},
{"dumpThreads"."([" THD "The [[" STE, (void *)&JVM_DumpThreads},
{"setNativeName"."(" STR ")V", (void *)&JVM_SetNativeThreadName},
};
Copy the code
- Source: github.com/unofficial-…
- As you can see from the definition,
start0
Method will execute&JVM_StartThread
Method, which ultimately starts the thread at the JVM level.
3. JVM creates threads
3.1 JVM_StartThread
Source: github.com/JetBrains/j…
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_StartThread");
JavaThread *native_thread = NULL;
// Create a thread
native_thread = new JavaThread(&thread_entry, sz);
// Start the thread
Thread::start(native_thread);
JVM_END
Copy the code
- This is a lot of code, but the core is
Create a thread
andStarting a thread
And the other&thread_entry
Also a method, as follows:
Thread_entry, thread entry
static void thread_entry(JavaThread* thread, TRAPS) {
HandleMark hm(THREAD);
Handle obj(THREAD, thread->threadObj());
JavaValue result(T_VOID);
JavaCalls::call_virtual(&result,
obj,
KlassHandle(THREAD, SystemDictionary::Thread_klass()),
vmSymbols::run_method_name(),
vmSymbols::void_method_signature(),
THREAD);
}
Copy the code
Importantly, thread_entry includes the Java callback JavaCalls::call_virtual when the thread is created to introduce this thread entry method. This callback function is called by the JVM.
VmSymbols ::run_method_name() is the method that can be called back.
Source: github.com/JetBrains/j…
#define VM_SYMBOLS_DO(template, do_alias)
template(run_method_name, "run")
Copy the code
- this
run
This is the run method that will be called in our Java program. Next we follow the code execution link to find out when the callback method was called.
3.2 JavaThread
native_thread = new JavaThread(&thread_entry, sz);
Copy the code
Next, let’s move on to the source code implementation of JavaThread.
Source: github.com/JetBrains/j…
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
Thread()
#if INCLUDE_ALL_GCS
, _satb_mark_queue(&_satb_mark_queue_set),
_dirty_card_queue(&_dirty_card_queue_set)
#endif // INCLUDE_ALL_GCS
{
if (TraceThreadEvents) {
tty->print_cr("creating thread %p".this);
}
initialize();
_jni_attach_state = _not_attaching_via_jni;
set_entry_point(entry_point);
// Create the native thread itself.
// %note runtime_23
os::ThreadType thr_type = os::java_thread;
thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread :os::java_thread;
os::create_thread(this, thr_type, stack_sz);
}
Copy the code
ThreadFunction entry_point
The one above usthread_entry
Methods.size_t stack_sz
Indicates the number of existing threads in the process.- These two parametersWill be passed to
os::create_thread
Method for creating threads to use.
OS: 3.3: create_thread
Source:
os_linux.cpp
:Github.com/JetBrains/j…os_windows.cpp
:Github.com/JetBrains/j…
We all know what the JVM is! So its OS service implementation, Liunx, Windows, etc., all implement thread creation logic. This is a bit like the adapter pattern
os_linux -> os::create_thread
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
assert(thread->osthread() == NULL, "caller responsible");
// Allocate the OSThread object
OSThread* osthread = new OSThread(NULL, NULL);
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED);
pthread_t tid;
int ret = pthread_create(&tid, &attr, (void* (*) (void*)) java_start, thread);
return true;
}
Copy the code
osthread->set_state(ALLOCATED)
, initializes the allocated state, but is not initialized at this time.pthread_create
, is a thread creation function for UNIx-like operating systems (Unix, Linux, Mac OS X, and so on).java_start
, focusing on the class, is the method that actually creates the thread.
3.4 java_start
Source: github.com/JetBrains/j…
static void *java_start(Thread *thread) {
/ / thread ID
int pid = os::current_process_id();
// Set the thread
ThreadLocalStorage::set_thread(thread);
// Set the thread state: INITIALIZED The initialization is complete
osthread->set_state(INITIALIZED);
// Wake up all threads
sync->notify_all();
// loop to initialize the state and wait for wait
while (osthread->get_state() == INITIALIZED) {
sync->wait(Mutex::_no_safepoint_check_flag);
}
// Wait to wake up and execute the run method
thread->run();
return 0;
}
Copy the code
- The JVM sets the thread state, and INITIALIZED completes.
sync->notify_all()
To wake up all threads.osthread->get_state() == INITIALIZED
The while loop waitsthread->run()
Is executed after the thread wakes up, i.e. after the state changes.This is also shown in our thread execution UML diagram
4. JVM starts the thread
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_StartThread");
JavaThread *native_thread = NULL;
// Create a thread
native_thread = new JavaThread(&thread_entry, sz);
// Start the thread
Thread::start(native_thread);
JVM_END
Copy the code
JVM_StartThread
There are two steps in creating (new JavaThread
), start (Thread::start
). Now that the creation process is over, let’s talk about startup.
Thread: 4.1: start
Source: github.com/JetBrains/j…
void Thread::start(Thread* thread) {
trace("start", thread);
if(! DisableStartThread) {if (thread->is_Java_thread()) {
java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),
java_lang_Thread::RUNNABLE);
}
// Different OS will have different startup code logicos::start_thread(thread); }}Copy the code
- If threads are not disabled
DisableStartThread
And it’s a Java threadthread->is_Java_thread()
, then set the thread state toRUNNABLE
. os::start_thread(thread)
Call the thread-start method.Different OS will have different startup code logic
OS: 4.2: start_thread (thread)
Source: github.com/JetBrains/j…
void os::start_thread(Thread* thread) {
// guard suspend/resume
MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
OSThread* osthread = thread->osthread();
osthread->set_state(RUNNABLE);
pd_start_thread(thread);
}
Copy the code
osthread->set_state(RUNNABLE)
To set the thread stateRUNNABLE
pd_start_thread(thread)
, start the thread, this is by each OS implementation class, to achieve their own system start method.For example, Windows and Linux code are completely different.
4.3 pd_start_thread (thread)
Source: github.com/JetBrains/j…
void os::pd_start_thread(Thread* thread) {
OSThread * osthread = thread->osthread();
assert(osthread->get_state() ! = INITIALIZED,"just checking");
Monitor* sync_with_child = osthread->startThread_lock();
MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
sync_with_child->notify();
}
Copy the code
- This part of the code
notify()
Most importantly, it wakes up the thread. - When the thread wakes up,
3.4 the thread - > run ();
You can continue to execute.
5. JVM thread callback
5.1 the thread – > run () [JavaThread: : run ()]
Source: github.com/JetBrains/j…
// The first routine called by a new Java thread
void JavaThread::run() {
/ /... Initialize thread operations
thread_main_inner();
}
Copy the code
- Os_linux.cpp: JavaThread::run();
- This is the part where you have to go further,
thread_main_inner();
Methods.
5.2 thread_main_inner
Source: github.com/JetBrains/j…
void JavaThread::thread_main_inner() {
if (!this->has_pending_exception() && ! java_lang_Thread::is_stillborn(this->threadObj())) {
{
ResourceMark rm(this);
this->set_native_thread_name(this->get_thread_name());
}
HandleMark hm(this);
this->entry_point()(this.this);
}
DTRACE_THREAD_PROBE(stop, this);
this->exit(false);
delete this;
}
Copy the code
- Here’s the thread name of the Settings you’re familiar with,
this->set_native_thread_name(this->get_thread_name())
. this->entry_point()
The thread_entry method in 3.1 is actually called.thread_entry
The method will eventually be calledJavaCalls::call_virtual
In thevmSymbols::run_method_name()
. The run() method completes the thread startup.Finally it’s back!
Five, the summary
- Thread startup involves the JVM, so it’s really hard to know as much from a native approach as it is without a thorough understanding.
- The whole source code analysis can be combined with the code to call the UML sequence diagram for learning, the basic core process includes:
Java creates threads and starts them
,Call the local method start0()
,Creation and start of JVM_StartThread in the JVM
,Set the thread state wait to wake up
,Start the thread and wake it up depending on the OS
,Finally, the callback to the run() method starts the Java thread
. - Sometimes it may just be a very simple method, but it will also have its depth. After really understanding, there is no need to memorize by rote.If you need to obtain the above large hd picture, you can add small Fuge wechat (
fustack
), note: Thread large picture
Six, series recommendation
- Why does HashCode use 31 as a multiplier?
- What does HashMap disturbance function, load factor do?
- LinkedList inserts faster than ArrayList? Are you sure?
- AQS principle analysis and practical use of ReentrantLock
- ThreadLocal open addressing? If you ask me that, I’ll hang up!