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:

  1. Thread.c:Github.com/unofficial-…
  2. jvm.cpp:Github.com/JetBrains/j…
  3. thread.cpp:Github.com/JetBrains/j…
  4. os.cpp:Github.com/JetBrains/j…
  5. os_linux.cpp:Github.com/JetBrains/j…
  6. os_windows.cpp:Github.com/JetBrains/j…
  7. 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 methodstart()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 additionstart()Is asynchronizedMethod, 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,interrupt0And 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,start0Method will execute&JVM_StartThreadMethod, 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 isCreate a threadandStarting a threadAnd the other&thread_entryAlso 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
  • thisrunThis 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_pointThe one above usthread_entryMethods.
  • size_t stack_szIndicates the number of existing threads in the process.
  • These two parametersWill be passed toos::create_threadMethod 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() == INITIALIZEDThe while loop waits
  • thread->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_StartThreadThere 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 disabledDisableStartThreadAnd 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 codenotify()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_entryThe method will eventually be calledJavaCalls::call_virtualIn 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!