深入Java Thread底层实现

版权声明:本文为CSDN博主「summer_west_fish」的原创文章
原文链接:https://blog.csdn.net/summer_fish/article/details/108408572

深入Java Thread底层实现

Thread start 源码揭秘

java.lang.Thread # start()

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 */
        }
    }
}

从上面的代码中,我们可以发现它会先去 判断 threadStatus 是不是 0, 不是的话会抛出异常 。

在 Thread 源码中我们可以发现 threadStatus 默认值就是 0

 /* Java thread status for tools,
  * initialized to indicate thread 'not yet started'
  */
 private volatile int threadStatus = 0;
  • 那什么时候会被改变呢?
  • 这个 threadStatus 都有哪些值呢?

start0

状态的改变肯定伴随着线程的启动,所以我们直接来到下面这个 start0方法

private native void start0();

Path:src/java.base/share/native/libjava/Thread.c

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},
    {"countStackFrames", "()I",        (void *)&JVM_CountStackFrames},
    {"interrupt0",       "()V",        (void *)&JVM_Interrupt},
    {"isInterrupted",    "(Z)Z",       (void *)&JVM_IsInterrupted},
    {"holdsLock",        "(" OBJ ")Z", (void *)&JVM_HoldsLock},
    {"getThreads",        "()[" THD,   (void *)&JVM_GetAllThreads},
    {"dumpThreads",      "([" THD ")[[" STE, (void *)&JVM_DumpThreads},
    {"setNativeName",    "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};

jvm.cpp # JVM_StartThread()

Path: jdk\src\share\javavm\export\jvm.h

/*
 * java.lang.Thread
 */
JNIEXPORT void JNICALL
JVM_StartThread(JNIEnv *env, jobject thread);

提示:这里 JNIEXPORT 和 JNICALL 都是 JNI 的关键字,表示此函数是要被 JNI 调用的

Path: hotspot/src/hotspot/share/prims/jvm.cpp

  • 创建线程: new JavaThread(&thread_entry, sz)
  • 启动线程: Thread::start(native_thread);
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
  JVMWrapper("JVM_StartThread");
  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;

      // ===============================================================
      // 创建C++级别的本地线程,&thread_entry为线程run方法执行入口
      // ===============================================================
      native_thread = new JavaThread(&thread_entry, sz);

      // 检查该本地线程中是否包含OSThread,因为可能出现由于内存不足导致OSThread未创建成功的情况
      if (native_thread->osthread() != NULL) {
        // Note: the current thread is not being used within "prepare".
        // ===============================================================
        // 准备Java本地线程,链接Java线程 <-> C++线程
        // ===============================================================
        native_thread->prepare(jthread);
      }
    }
  }

  // ===============================================================
  // 启动Java本地线程
  // ===============================================================
  Thread::start(native_thread);

JVM_END

**提示:**这里 JVM_ENTRY 和 JVM_END是两个宏定义,定义了函数体的头和尾。

创建线程

thread.cpp # JavaThread::JavaThread()

native_thread = new JavaThread(&thread_entry, sz);

线程构造器

Path: src/hotspot/share/runtime/thread.cpp

// C++级别Java线程构造方法
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
{
  // 初始化实例变量
  initialize();
  _jni_attach_state = _not_attaching_via_jni;
  
  // ============================================= 
  // 设置Java执行线程入口,最终会调用
  // =============================================  
  set_entry_point(entry_point);
  // 创建系统级本地线程
  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);
}

创建内核线程:os::create_thread(this, thr_type, stack_sz);

创建内核线程

Path:hotspot/src/hotspot/os/linux/os_linux.cpp

bool os::create_thread(Thread* thread, ThreadType thr_type,
                       size_t req_stack_size) {
  // 创建操作系统线程
  OSThread* osthread = new OSThread(NULL, NULL);
  if (osthread == NULL) {
    return false;
  }
  
  // 把osthread状态设置为已分配
  osthread->set_state(ALLOCATED);
  // 绑定至JavaThread
  thread->set_osthread(osthread);
  // 初始化线程数形
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

  ThreadState state;
  {
    pthread_t tid;
    // ========================================================
    // 调用系统库创建线程,thread_native_entry为本地Java线程执行入口
    // ========================================================
    int ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread);

    if (ret != 0) {
      // Need to clean up stuff we've allocated so far
      thread->set_osthread(NULL);
      delete osthread;
      return false;
    }

    // Store pthread info into the OSThread
    osthread->set_pthread_id(tid);

    // Wait until child thread is either initialized or aborted
    {
      Monitor* sync_with_child = osthread->startThread_lock();
      MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
      while ((state = osthread->get_state()) == ALLOCATED) {
        sync_with_child->wait(Mutex::_no_safepoint_check_flag);
      }
    }
  }
  
  return true;
}

终于看到有点眼熟的函数了~ 哈哈哈

// Linux系统函数 pthread_create()
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);

os_linux.cpp # *thread_native_entry()

thread_native_entry为本地Java线程执行入口

// 线程执行入口
// Thread start routine for all newly created threads
static void *thread_native_entry(Thread *thread) {

  // 初始化当前线程,把当前线程加入到TLS里
  thread->initialize_thread_current();

  OSThread* osthread = thread->osthread();
  // 获取同步锁
  Monitor* sync = osthread->startThread_lock();
  osthread->set_thread_id(os::current_thread_id());

  // handshaking with parent thread
  {
    MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);

    // notify parent thread
    osthread->set_state(INITIALIZED);
    sync->notify_all();

    // 等待调用os::start_thread(),然后继续执行
    while (osthread->get_state() == INITIALIZED) {
      sync->wait(Mutex::_no_safepoint_check_flag);
    }
  }

  

  // =======================================================
  // 调用JavaThread的run方法以便触发执行java.lang.Thread.run()
  // =======================================================
  thread->run();

  return 0;
}

启动线程

另一个重点 : 初始化工作完成之后当前线程wait,等待调用Thread::start(native_thread);

Thread::start(native_thread);

Path: hotspot\src\share\vm\runtime\thread.cpp

void Thread::start(Thread* thread) {

  if (!DisableStartThread) {
    if (thread->is_Java_thread()) {
      // 设置线程状态为RUNNABLE
      java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(), java_lang_Thread::RUNNABLE);
    }
    // 启动本地线程
    os::start_thread(thread);
  }
}

在启动该线程之前,将线程状态初始化为 RUNNABLE。

不能在线程启动后设置,因为我们不知道 正确的线程状态,它可能在 MONITOR_WAIT 或 在睡眠或其他状态。

启动内核线程

Path: src/hotspot/share/runtime/os.cpp

void os::start_thread(Thread* thread) {
  // guard suspend/resume
  MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
  OSThread* osthread = thread->osthread();
  // osthread状态设为运行中
  osthread->set_state(RUNNABLE);
  // 最终启动线程
  pd_start_thread(thread);
}

os_linux.cpp # os::pd_start_thread()

最终启动线程,位于src/hotspot/os/linux/os_linux.cpp,通知子线程JavaThread继续往下执行

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();
}

全局函数notify

bool Monitor::notify() {
  assert (_owner == Thread::current(), "invariant") ;
  assert (ILocked(), "invariant") ;
  if (_WaitSet == NULL) return true ;
  NotifyCount ++ ;

  // Transfer one thread from the WaitSet to the EntryList or cxq.
  // Currently we just unlink the head of the WaitSet and prepend to the cxq.
  // And of course we could just unlink it and unpark it, too, but
  // in that case it'd likely impale itself on the reentry.
  Thread::muxAcquire (_WaitLock, "notify:WaitLock") ;
  ParkEvent * nfy = _WaitSet ;
  if (nfy != NULL) {                  // DCL idiom
    _WaitSet = nfy->ListNext ;
    assert (nfy->Notified == 0, "invariant") ;
    // push nfy onto the cxq
    for (;;) {
      const intptr_t v = _LockWord.FullWord ;
      assert ((v & 0xFF) == _LBIT, "invariant") ;
      nfy->ListNext = (ParkEvent *)(v & ~_LBIT);
      if (CASPTR (&_LockWord, v, UNS(nfy)|_LBIT) == v) break;
      // interference - _LockWord changed -- just retry
    }
    // Note that setting Notified before pushing nfy onto the cxq is
    // also legal and safe, but the safety properties are much more
    // subtle, so for the sake of code stewardship ...
    OrderAccess::fence() ;
    nfy->Notified = 1;
  }
  Thread::muxRelease (_WaitLock) ;
  if (nfy != NULL && (NativeMonitorFlags & 16)) {
    // Experimental code ... light up the wakee in the hope that this thread (the owner)
    // will drop the lock just about the time the wakee comes ONPROC.
    nfy->unpark() ;
  }
  assert (ILocked(), "invariant") ;
  return true ;
}

惊喜,居然在这个代码中看到这段注释,这里提到 WaitSet , EntryList,cxq
这是 隐式锁 [[Synchronized 内部的实现原理呀]] 或者 称它为 [[Monitor机制]]

  • WaitSet: 是一个等待队列,存放进入等待状态的线程
  • cxq: 是一个竞争队列,所有请求锁🔒的线程会先到这里
  • EntryList: 存放 cxq 中有资格成为候选资源去竞争锁的线程

运行线程

thread.cpp # JavaThread::run()
这里调用JavaThread的run方法以便执行java.lang.Thread.run()用户逻辑代码,位于src/hotspot/share/runtime/thread.cpp

void JavaThread::run() {


  // 执行run方法前的初始化和缓存工作
  this->initialize_tlab();

  ...

  // 通知JVMTI
  if (JvmtiExport::should_post_thread_life()) {
    JvmtiExport::post_thread_start(this);
  }

  EventThreadStart event;
  if (event.should_commit()) {
    event.set_thread(THREAD_TRACE_ID(this));
    event.commit();
  }

  // ==================================================
  // 执行Java级别Thread类run()方法内容
  // ==================================================
  thread_main_inner();

}


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);

    // ==========================================
    // 执行线程入口java.lang.Thread # run()方法
    // ==========================================
    this->entry_point()(this, this);
  }

  DTRACE_THREAD_PROBE(stop, this);

  // 退出并释放空间
  this->exit(false);
  // 释放资源
  delete this;
}

jvm.cpp # thread_entry()

最终执行实例化JavaThread时设置的入口方法entry_point,代表了Java代码级别Java线程执行入口, 这里通过JavaCalls组件调用java.lang.Thread.run()方法,执行真正的用户逻辑代码。

static void thread_entry(JavaThread* thread, TRAPS) {
  HandleMark hm(THREAD);
  Handle obj(THREAD, thread->threadObj());
  JavaValue result(T_VOID);
  // 执行Java调用
  JavaCalls::call_virtual(&result,
                          obj,
                          SystemDictionary::Thread_klass(),
                          vmSymbols::run_method_name(),
                          vmSymbols::void_method_signature(),
                          THREAD);
}

线程状态

threadStatus 都有哪些值呢?

/*
 * Java thread state support
 */
enum {
    JAVA_THREAD_STATE_NEW           = 0,
    JAVA_THREAD_STATE_RUNNABLE      = 1,
    JAVA_THREAD_STATE_BLOCKED       = 2,
    JAVA_THREAD_STATE_WAITING       = 3,
    JAVA_THREAD_STATE_TIMED_WAITING = 4,
    JAVA_THREAD_STATE_TERMINATED    = 5,
    JAVA_THREAD_STATE_COUNT         = 6
};

惊喜,居然在这个代码中看到这段注释,这里提到 WaitSet , EntryList,cxq
这是 隐式锁 [[Synchronized 内部的实现原理呀]] 或者 称它为 [[Monitor机制]]

WaitSet: 是一个等待队列,存放进入等待状态的线程
cxq: 是一个竞争队列,所有请求锁🔒的线程会先到这里
EntryList: 存放 cxq 中有资格成为候选资源去竞争锁的线程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值