Thread 管理#

Threads List#

Thread C++ 对象:

  • 所有线程都是Thread C++ class的实例 ;

  • 所有执行 Java 代码的线程都是 JavaThread C++ class( Thread C++ class 的子类) 实例。

虚拟机会在一个称为 ThreadsList ThreadsSMRSupport::_java_thread_list 的链接列表中跟踪所有线程,该列表受 Threads_lock 保护,Threads_lock 是虚拟机中使用的重要 同步锁 之一。

ThreadsList#

src/hotspot/share/runtime/threadSMR.hpp

// A fast list of JavaThreads.
//
class ThreadsList : public CHeapObj<mtThread> {
  uint _magic;
  const uint _length;
  ThreadsList* _next_list;
  JavaThread *const *const _threads;
  volatile intx _nested_handle_cnt;
  static ThreadsList* add_thread(ThreadsList* list, JavaThread* java_thread);
  static ThreadsList* remove_thread(ThreadsList* list, JavaThread* java_thread);

ThreadsSMRSupport#

src/hotspot/share/runtime/threadSMR.hpp

class ThreadsSMRSupport : AllStatic {
  static ThreadsList           _bootstrap_list;
  static ThreadsList* volatile _java_thread_list;

  static void add_thread(JavaThread *thread);
  static ThreadsList* get_java_thread_list();

src/hotspot/share/runtime/threadSMR.cpp

// The bootstrap list is empty and cannot be freed.
static ThreadsList ThreadsSMRSupport::_bootstrap_list{0};

// This is the VM's current "threads list" and it contains all of
// the JavaThreads the VM considers to be alive at this moment in
// time. The other ThreadsList objects in the VM contain past
// snapshots of the "threads list". _java_thread_list is initially
// set to _bootstrap_list so that we can detect when we have a very
// early use of a ThreadsListHandle.
static ThreadsList* volatile ThreadsSMRSupport::_java_thread_list = &_bootstrap_list;

src/hotspot/share/runtime/threadSMR.inline.hpp

inline ThreadsList* ThreadsSMRSupport::get_java_thread_list() {
  return (ThreadsList*)Atomic::load_acquire(&_java_thread_list);
}

Threads#

src/hotspot/share/runtime/threads.cpp

static void Threads::add(JavaThread* p, bool force_daemon) {
  // The threads lock must be owned at this point
  assert(Threads_lock->owned_by_self(), "must have threads lock");

  BarrierSet::barrier_set()->on_thread_attach(p);

  // Once a JavaThread is added to the Threads list, smr_delete() has
  // to be used to delete it. Otherwise we can just delete it directly.
  p->set_on_thread_list();

  _number_of_threads++;
  oop threadObj = p->threadObj();
  bool daemon = true;
  // Bootstrapping problem: threadObj can be null for initial
  // JavaThread (or for threads attached via JNI)
  if (!force_daemon &&
      (threadObj == nullptr || !java_lang_Thread::is_daemon(threadObj))) {
    _number_of_non_daemon_threads++;
    daemon = false;
  }

  ThreadService::add_thread(p, daemon);

  // Maintain fast thread list
  ThreadsSMRSupport::add_thread(p);

  // Increase the ObjectMonitor ceiling for the new thread.
  ObjectSynchronizer::inc_in_use_list_ceiling();

  // Possible GC point.
  Events::log(p, "Thread added: " INTPTR_FORMAT, p2i(p));

  // Make new thread known to active EscapeBarrier
  EscapeBarrier::thread_added(p);
}

Threads_lock#

虚拟机会在一个称为 ThreadsList ThreadsSMRSupport::_java_thread_list 的链接列表中跟踪所有线程,该列表受 Threads_lock 保护,Threads_lock 是虚拟机中使用的重要 同步锁 之一。

src/hotspot/share/runtime/mutexLocker.hpp

extern Monitor* Threads_lock;                    // a lock on the Threads table of active Java threads

Thread List 初始化#

JVM 初始化阶段初始化 ThreadsList ThreadsSMRSupport::_bootstrap_list

1: libjvm.so!ThreadsList::ThreadsList(ThreadsList * const this, int entries) /jdk/src/hotspot/share/runtime/threadSMR.cpp:660)
2: libjvm.so!__static_initialization_and_destruction_0(int __initialize_p, int __priority) /jdk/src/hotspot/share/runtime/threadSMR.cpp:83)
3: libjvm.so!_GLOBAL__sub_I_threadSMR.cpp(void)() /jdk/src/hotspot/share/runtime/threadSMR.cpp:1290)
4: ...
5: ___dlopen(const char * file, int mode) (dlopen.c:81)
6: libjli.so!LoadJavaVM(const char * jvmpath, InvocationFunctions * ifn) /jdk/src/java.base/unix/native/libjli/java_md.c:539)
7: libjli.so!JLI_Launch(int argc, char ** argv, int jargc, const char ** jargv, int appclassc, const char ** appclassv, const char * fullversion, const char * dotversion, const char * pname, const char * lname, jboolean javaargs, jboolean cpwildcard, jboolean javaw, jint ergo) /jdk/src/java.base/share/native/libjli/java.c:295)
8: main(int argc, char ** argv) /jdk/src/java.base/share/native/launcher/main.c:166)

Java main thead 初始化阶段初始化 ThreadsList ThreadsSMRSupport::_java_thread_list

01: libjvm.so!ThreadsList::ThreadsList(ThreadsList * const this, int entries) /jdk/src/hotspot/share/runtime/threadSMR.cpp:660)
02: libjvm.so!ThreadsList::add_thread(ThreadsList * list, JavaThread * java_thread) /jdk/src/hotspot/share/runtime/threadSMR.cpp:681)
03: libjvm.so!ThreadsSMRSupport::add_thread(JavaThread * thread) /jdk/src/hotspot/share/runtime/threadSMR.cpp:857)
04: libjvm.so!Threads::add(JavaThread * p, bool force_daemon) /jdk/src/hotspot/share/runtime/threads.cpp:999)
05: libjvm.so!Threads::create_vm(JavaVMInitArgs * args, bool * canTryAgain) /jdk/src/hotspot/share/runtime/threads.cpp:565)
06: libjvm.so!JNI_CreateJavaVM_inner(JavaVM ** vm, void ** penv, void * args) /jdk/src/hotspot/share/prims/jni.cpp:3577)
07: libjvm.so!JNI_CreateJavaVM(JavaVM ** vm, void ** penv, void * args) /jdk/src/hotspot/share/prims/jni.cpp:3668)
08: libjli.so!InitializeJVM(JavaVM ** pvm, JNIEnv ** penv, InvocationFunctions * ifn) /jdk/src/java.base/share/native/libjli/java.c:1506)
09: libjli.so!JavaMain(void * _args) /jdk/src/java.base/share/native/libjli/java.c:415)
10: libjli.so!ThreadJavaMain(void * args) /jdk/src/java.base/unix/native/libjli/java_md.c:650)
11: start_thread(void * arg) (pthread_create.c:442)
12: clone3() (clone3.S:81)

thread 注册#

从 c++ 代码看,thread 注册入口在: Threads::add(JavaThread* p, bool force_daemon) 。调用前一定要加全局锁 Threads_lock

main java thread 的注册#

Call stack 如下:

01: libjvm.so!ThreadsList::ThreadsList(ThreadsList * const this, int entries) /jdk/src/hotspot/share/runtime/threadSMR.cpp:660)
02: libjvm.so!ThreadsList::add_thread(ThreadsList * list, JavaThread * java_thread) /jdk/src/hotspot/share/runtime/threadSMR.cpp:681)
03: libjvm.so!ThreadsSMRSupport::add_thread(JavaThread * thread) /jdk/src/hotspot/share/runtime/threadSMR.cpp:857)
04: libjvm.so!Threads::add(JavaThread * p, bool force_daemon) /jdk/src/hotspot/share/runtime/threads.cpp:999)
05: libjvm.so!Threads::create_vm(JavaVMInitArgs * args, bool * canTryAgain) /jdk/src/hotspot/share/runtime/threads.cpp:565)
06: libjvm.so!JNI_CreateJavaVM_inner(JavaVM ** vm, void ** penv, void * args) /jdk/src/hotspot/share/prims/jni.cpp:3577)
07: libjvm.so!JNI_CreateJavaVM(JavaVM ** vm, void ** penv, void * args) /jdk/src/hotspot/share/prims/jni.cpp:3668)
08: libjli.so!InitializeJVM(JavaVM ** pvm, JNIEnv ** penv, InvocationFunctions * ifn) /jdk/src/java.base/share/native/libjli/java.c:1506)
09: libjli.so!JavaMain(void * _args) /jdk/src/java.base/share/native/libjli/java.c:415)
10: libjli.so!ThreadJavaMain(void * args) /jdk/src/java.base/unix/native/libjli/java_md.c:650)
11: start_thread(void * arg) (pthread_create.c:442)
12: clone3() (clone3.S:81)

而其中 Threads::create_vm(...) 中创建了 main java thread 的 JavaThread 对象: src/hotspot/share/runtime/threads.cpp

jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
...
  // Initialize OopStorage for threadObj
  JavaThread::_thread_oop_storage = OopStorageSet::create_strong("Thread OopStorage", mtThread);

  // Attach the main thread to this os thread
  JavaThread* main_thread = new JavaThread();
  main_thread->set_thread_state(_thread_in_vm);
  main_thread->initialize_thread_current();
  // must do this before set_active_handles
  main_thread->record_stack_base_and_size();
  main_thread->register_thread_stack_with_NMT();
  main_thread->set_active_handles(JNIHandleBlock::allocate_block());
  ...
  // Add main_thread to threads list to finish barrier setup with
  // on_thread_attach.  Should be before starting to build Java objects in
  // init_globals2, which invokes barriers.
  {
    MutexLocker mu(Threads_lock);
    Threads::add(main_thread);
  }

可见,对 thread list 的 add,使用了上文中的 Threads_lock

pure java Thread 的注册#

对于在 java code 中用 new java.lang.Thread 创建的 thread.

Call stack:

libjvm.so!ThreadsList::add_thread(ThreadsList * list, JavaThread * java_thread) (/jdk/src/hotspot/share/runtime/threadSMR.cpp:678)
libjvm.so!ThreadsSMRSupport::add_thread(JavaThread * thread) (/jdk/src/hotspot/share/runtime/threadSMR.cpp:857)
libjvm.so!Threads::add(JavaThread * p, bool force_daemon) (/jdk/src/hotspot/share/runtime/threads.cpp:999)
libjvm.so!JavaThread::prepare(JavaThread * const this, jobject jni_thread, ThreadPriority prio) (/jdk/src/hotspot/share/runtime/javaThread.cpp:1684)
libjvm.so!JVM_StartThread(JNIEnv * env, jobject jthread) (/jdk/src/hotspot/share/prims/jvm.cpp:2991)
[Unknown/Just-In-Time compiled code] (Unknown Source:0)

thread list iterator#

Iterate thread list. 可以保证在替代 thread list 过程中 JavaThread c++ 对象不会被 c++ delete 。但不保存 JavaThread 对应的线程不会退出。

src/hotspot/share/runtime/threadSMR.hpp

// Thread Safe Memory Reclamation (Thread-SMR) support.
//
// ThreadsListHandles are used to safely perform operations on one or more
// threads without the risk of the thread or threads exiting during the
// operation. It is no longer necessary to hold the Threads_lock to safely
// perform an operation on a target thread.
//
// There are several different ways to refer to java.lang.Thread objects
// so we have a few ways to get a protected JavaThread *:
//
// JNI jobject example:
//   jobject jthread = ...;
//   :
//   ThreadsListHandle tlh;
//   JavaThread* jt = nullptr;
//   bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &jt, nullptr);
//   if (is_alive) {
//     :  // do stuff with 'jt'...
//   }
//
// JVM/TI jthread example:
//   jthread thread = ...;
//   :
//   JavaThread* jt = nullptr;
//   ThreadsListHandle tlh;
//   jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &jt, nullptr);
//   if (err != JVMTI_ERROR_NONE) {
//     return err;
//   }
//   :  // do stuff with 'jt'...
//
// JVM/TI oop example (this one should be very rare):
//   oop thread_obj = ...;
//   :
//   JavaThread *jt = nullptr;
//   ThreadsListHandle tlh;
//   jvmtiError err = JvmtiExport::cv_oop_to_JavaThread(tlh.list(), thread_obj, &jt);
//   if (err != JVMTI_ERROR_NONE) {
//     return err;
//   }
//   :  // do stuff with 'jt'...
//
// A JavaThread * that is included in the ThreadsList that is held by
// a ThreadsListHandle is protected as long as the ThreadsListHandle
// remains in scope. The target JavaThread * may have logically exited,
// but that target JavaThread * will not be deleted until it is no
// longer protected by a ThreadsListHandle.
//
// SMR Support for the Threads class.
//
...
// This stack allocated ThreadsListHandle keeps all JavaThreads in the
// ThreadsList from being deleted until it is safe.
//
class ThreadsListHandle : public StackObj {
  friend class ThreadsListHandleTest;  // for _list_ptr access

  SafeThreadsListPtr _list_ptr;
  elapsedTimer _timer;  // Enabled via -XX:+EnableThreadSMRStatistics.

public:
  ThreadsListHandle(Thread *self = Thread::current());
  ~ThreadsListHandle();

  ThreadsList *list() const {
    return _list_ptr.list();
  }

  using Iterator = ThreadsList::Iterator;
  inline Iterator begin();
  inline Iterator end();

  bool cv_internal_thread_to_JavaThread(jobject jthread, JavaThread ** jt_pp, oop * thread_oop_p);

  bool includes(JavaThread* p) {
    return list()->includes(p);
  }

  uint length() const {
    return list()->length();
  }

  JavaThread *thread_at(uint i) const {
    return list()->thread_at(i);
  }
};
...
// This stack allocated ThreadsListHandle and JavaThreadIterator combo
// is used to walk the ThreadsList in the included ThreadsListHandle
// using the following style:
//
//   for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
//     ...
//   }
//
class JavaThreadIteratorWithHandle : public StackObj {
  ThreadsListHandle _tlh;
  uint _index;

public:
  JavaThreadIteratorWithHandle() : _index(0) {}

  uint length() const {
    return _tlh.length();
  }

  ThreadsList *list() const {
    return _tlh.list();
  }

  JavaThread *next() {
    if (_index >= length()) {
      return nullptr;
    }
    return _tlh.list()->thread_at(_index++);
  }

  void rewind() {
    _index = 0;
  }
};