zoukankan      html  css  js  c++  java
  • java中Thread启动流程分析

    前言

    进程是操作系统进行资源分配和调度的基本单位,线程是操作系统能够进行运算调度的最小单位,一个进程可以有很多线程,每个线程并行执行不同的任务,java中的线程就是Thread类。

    简单使用

    public class Client {
    
      public static void main(String[] args) {
        Thread testThread = new Thread(() -> {
          System.out.println(Thread.currentThread().getName() + " is running");
        });
        testThread.setName("TestThread");
        testThread.start();
        System.out.println(Thread.currentThread().getName() + " is running");
      }
    
    }
    

    输出结果为

    main is running
    TestThread is running
    

    创建一个名称为TestThread的线程并启动。

    源码分析

        /**
         * 启动线程,JVM会调用run()方法
         */
        public synchronized void start() {
            /**
             * This method is not invoked for the main method thread or "system"
             * group threads created/set up by the VM. Any new functionality added
             * to this method in the future may have to also be added to the VM.
             *
             * A zero status value corresponds to state "NEW".
             */
            if (threadStatus != 0)
                throw new IllegalThreadStateException();
    
            /* Notify the group that this thread is about to be started
             * so that it can be added to the group's list of threads
             * and the group's unstarted count can be decremented. */
            group.add(this);
    
            boolean started = false;
            try {
                start0();
                started = true;
            } finally {
                try {
                    if (!started) {
                        group.threadStartFailed(this);
                    }
                } catch (Throwable ignore) {
                    /* do nothing. If start0 threw a Throwable then
                      it will be passed up the call stack */
                }
            }
        }
    
        private native void start0();
    

    启动流程会调用start0()方法,是一个本地方法,我们可以跟到openjdk源码中查看一下,这里以java11为例,github地址

    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 ")[[" STE, (void *)&JVM_DumpThreads},
        {"setNativeName",    "(" STR ")V", (void *)&JVM_SetNativeThreadName},
    };
    JNIEXPORT void JNICALL
    Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls)
    {
        (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));
    }
    

    路径为srcjava.baseshare ativelibjavaThread.c,可以看到start0()方法是通过JVM_StartThread()方法实现的。

    JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
      JavaThread *native_thread = NULL;
      bool throw_illegal_thread_state = false;
    
      // We must release the Threads_lock before we can post a jvmti event
      // in Thread::start.
      {
        // 获取互斥锁
        MutexLocker mu(Threads_lock);
    
        // 确保线程没有被启动
        if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) {
          throw_illegal_thread_state = true;
        } else {
          jlong size =
                 java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));
          NOT_LP64(if (size > SIZE_MAX) size = SIZE_MAX;)
          size_t sz = size > 0 ? (size_t) size : 0;
          native_thread = new JavaThread(&thread_entry, sz);
    
          // JavaThread constructor.
          if (native_thread->osthread() != NULL) {
            // Note: the current thread is not being used within "prepare".
            native_thread->prepare(jthread);
          }
        }
      }
    

    路径为srchotspotshareprimsjvm.cpp,是C++实现的。JavaThread表示jvm中的线程。

    JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : JavaThread() {
      _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 == &CompilerThread::thread_entry ? os::compiler_thread :
                                                                os::java_thread;
      // 创建一个操作系统层面的线程
      os::create_thread(this, thr_type, stack_sz);
    }
    

    路径为srchotspotshare untime hread.cpp。

    bool os::create_thread(Thread* thread, ThreadType thr_type,
                           size_t req_stack_size) {
      assert(thread->osthread() == NULL, "caller responsible");
    
      // Allocate the OSThread object
      OSThread* osthread = new OSThread(NULL, NULL);
      if (osthread == NULL) {
        return false;
      }
    
      // set the correct thread state
      osthread->set_thread_type(thr_type);
    
      // Initial state is ALLOCATED but not INITIALIZED
      osthread->set_state(ALLOCATED);
    
      thread->set_osthread(osthread);
    
      // init thread attributes
      pthread_attr_t attr;
      pthread_attr_init(&attr);
      pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    
      // Calculate stack size if it's not specified by caller.
      size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size);
      // In glibc versions prior to 2.7 the guard size mechanism
      // is not implemented properly. The posix standard requires adding
      // the size of the guard pages to the stack size, instead Linux
      // takes the space out of 'stacksize'. Thus we adapt the requested
      // stack_size by the size of the guard pages to mimick proper
      // behaviour. However, be careful not to end up with a size
      // of zero due to overflow. Don't add the guard page in that case.
      size_t guard_size = os::Linux::default_guard_size(thr_type);
      // Configure glibc guard page. Must happen before calling
      // get_static_tls_area_size(), which uses the guard_size.
      pthread_attr_setguardsize(&attr, guard_size);
    
      size_t stack_adjust_size = 0;
      if (AdjustStackSizeForTLS) {
        // Adjust the stack_size for on-stack TLS - see get_static_tls_area_size().
        stack_adjust_size += get_static_tls_area_size(&attr);
      } else {
        stack_adjust_size += guard_size;
      }
    
      stack_adjust_size = align_up(stack_adjust_size, os::vm_page_size());
      if (stack_size <= SIZE_MAX - stack_adjust_size) {
        stack_size += stack_adjust_size;
      }
      assert(is_aligned(stack_size, os::vm_page_size()), "stack_size not aligned");
    
      int status = pthread_attr_setstacksize(&attr, stack_size);
      if (status != 0) {
        // pthread_attr_setstacksize() function can fail
        // if the stack size exceeds a system-imposed limit.
        assert_status(status == EINVAL, status, "pthread_attr_setstacksize");
        log_warning(os, thread)("The %sthread stack size specified is invalid: " SIZE_FORMAT "k",
                                (thr_type == compiler_thread) ? "compiler " : ((thr_type == java_thread) ? "" : "VM "),
                                stack_size / K);
        thread->set_osthread(NULL);
        delete osthread;
        return false;
      }
    
      ThreadState state;
    
      {
        pthread_t tid;
        int ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread);
    }
    

    这个方法不同的操作系统有不同的实现,这里以linux为例,路径为srchotspotoslinuxos_linux.cpp。重点看pthread_create()方法中的thread_native_entry参数。

    // create new thread
    
    // Thread start routine for all newly created threads
    static void *thread_native_entry(Thread *thread) {
    
      thread->record_stack_base_and_size();
      static int counter = 0;
      int pid = os::current_process_id();
      alloca(((pid ^ counter++) & 7) * 128);
    
      thread->initialize_thread_current();
    
      OSThread* osthread = thread->osthread();
      Monitor* sync = osthread->startThread_lock();
    
      osthread->set_thread_id(os::current_thread_id());
    
      log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").",
        os::current_thread_id(), (uintx) pthread_self());
    
      if (UseNUMA) {
        int lgrp_id = os::numa_get_group_id();
        if (lgrp_id != -1) {
          thread->set_lgrp_id(lgrp_id);
        }
      }
      // initialize signal mask for this thread
      PosixSignals::hotspot_sigmask(thread);
    
      // initialize floating point control register
      os::Linux::init_thread_fpu_state();
    
      // handshaking with parent thread
      {
        MutexLocker ml(sync, Mutex::_no_safepoint_check_flag);
    
        // notify parent thread
        osthread->set_state(INITIALIZED);
        // 唤醒所有在等待的线程
        sync->notify_all();
    
        // wait until os::start_thread()
        while (osthread->get_state() == INITIALIZED) {
          sync->wait_without_safepoint_check();
        }
      }
    
      assert(osthread->pthread_id() != 0, "pthread_id was not set as expected");
    
      // 调用java中run()方法
      thread->call_run();
    }
    

    线程启动流程基本就是这样。

    参考

    Java并发系列-深入Jvm理解Thread启动流程

  • 相关阅读:
    前端开发 vue,angular,react框架对比1
    前端开发 Angular
    前端开发 Vue Vue.js和Node.js的关系
    net技术
    net技术方案
    软件工程项目费用计算
    前端开发 Vue -4promise解读2
    前端开发 Vue -4promise解读1
    mybatis与hibernate区别
    struts2和springmvc的区别
  • 原文地址:https://www.cnblogs.com/strongmore/p/14687054.html
Copyright © 2011-2022 走看看