jdk提供了接口用于获取所有线程的堆栈,

package thread;

import java.util.Map;

/**
 * Created by lpmoon on 2019/4/21.
 */
public class ThreadT {
    public static void main(String[] args) {
        Map<Thread, StackTraceElement[]> threadStackTraceMap = Thread.getAllStackTraces();
        for (Map.Entry<Thread, StackTraceElement[]> entry : threadStackTraceMap.entrySet()) {
            System.out.println(entry.getKey());
            for (StackTraceElement stackTraceElement : entry.getValue()) {
                System.out.println(stackTraceElement);
            }
            System.out.println("\n");
        }
    }
}

运行上面的代码可以看到如下的输出,

Thread[main,5,main]
java.lang.Thread.dumpThreads(Native Method)
java.lang.Thread.getAllStackTraces(Thread.java:1607)
thread.ThreadT.main(ThreadT.java:10)


Thread[Monitor Ctrl-Break,5,main]
java.util.Properties$LineReader.readLine(Properties.java:478)
java.util.Properties.load0(Properties.java:353)
java.util.Properties.load(Properties.java:341)
sun.net.NetProperties.loadDefaultProperties(NetProperties.java:70)
sun.net.NetProperties.access$000(NetProperties.java:41)

是不是跟jstack命令很像呢。getAllStackTraces通过调用native方法dumpThreads来获取堆栈数据。下面看一下这个方法是如何工作的(下面的内容基于Openjdk 8),

// Support for java.lang.Thread.getStackTrace() and getAllStackTraces() methods
// Return StackTraceElement[][], each element is the stack trace of a thread in
// the corresponding entry in the given threads array
JVM_ENTRY(jobjectArray, JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobjectArray threads))
  JVMWrapper("JVM_DumpThreads");
  JvmtiVMObjectAllocEventCollector oam;

  // Check if threads is null
  if (threads == NULL) {
    THROW_(vmSymbols::java_lang_NullPointerException(), 0);
  }

  objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(threads));
  objArrayHandle ah(THREAD, a);
  int num_threads = ah->length();
  // check if threads is non-empty array
  if (num_threads == 0) {
    THROW_(vmSymbols::java_lang_IllegalArgumentException(), 0);
  }

  // check if threads is not an array of objects of Thread class
  Klass* k = ObjArrayKlass::cast(ah->klass())->element_klass();
  if (k != SystemDictionary::Thread_klass()) {
    THROW_(vmSymbols::java_lang_IllegalArgumentException(), 0);
  }

  ResourceMark rm(THREAD);

  GrowableArray<instanceHandle>* thread_handle_array = new GrowableArray<instanceHandle>(num_threads);
  for (int i = 0; i < num_threads; i++) {
    oop thread_obj = ah->obj_at(i);
    instanceHandle h(THREAD, (instanceOop) thread_obj);
    thread_handle_array->append(h);
  }

  Handle stacktraces = ThreadService::dump_stack_traces(thread_handle_array, num_threads, CHECK_NULL);
  return (jobjectArray)JNIHandles::make_local(env, stacktraces());

JVM_END

上面的代码看起来比较长,但是其实核心代码都在ThreadService::dump_stack_traces()。之前的代码主要做一些鲁棒性检查,比如线程数组不能为null、数组长度不能为0、数组内的数据必须是线程。

Handle ThreadService::dump_stack_traces(GrowableArray<instanceHandle>* threads,
                                        int num_threads,
                                        TRAPS) {
  assert(num_threads > 0, "just checking");

  ThreadDumpResult dump_result;
  VM_ThreadDump op(&dump_result,
                   threads,
                   num_threads,
                   -1,    /* entire stack */
                   false, /* with locked monitors */
                   false  /* with locked synchronizers */);
  VMThread::execute(&op);

  // Allocate the resulting StackTraceElement[][] object

  ResourceMark rm(THREAD);
  Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_StackTraceElement_array(), true, CHECK_NH);
  ObjArrayKlass* ik = ObjArrayKlass::cast(k);
  objArrayOop r = oopFactory::new_objArray(ik, num_threads, CHECK_NH);
  objArrayHandle result_obj(THREAD, r);

  int num_snapshots = dump_result.num_snapshots();
  assert(num_snapshots == num_threads, "Must have num_threads thread snapshots");
  int i = 0;
  for (ThreadSnapshot* ts = dump_result.snapshots(); ts != NULL; i++, ts = ts->next()) {
    ThreadStackTrace* stacktrace = ts->get_stack_trace();
    if (stacktrace == NULL) {
      // No stack trace
      result_obj->obj_at_put(i, NULL);
    } else {
      // Construct an array of java/lang/StackTraceElement object
      Handle backtrace_h = stacktrace->allocate_fill_stack_trace_element_array(CHECK_NH);
      result_obj->obj_at_put(i, backtrace_h());
    }
  }

  return result_obj;
}

jvm内部通过一个异步线程来完成堆栈的收集,收集到的数据存放在ThreadDumpResult中,拿到数据后封装成对应的返回值。异步任务的实现是VM_ThreadDump,下面我们看一下这个任务的定义,

class VM_ThreadDump : public VM_Operation {
 private:
  ThreadDumpResult*              _result;
  int                            _num_threads;
  GrowableArray<instanceHandle>* _threads;
  int                            _max_depth;
  bool                           _with_locked_monitors;
  bool                           _with_locked_synchronizers;

  ThreadSnapshot* snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl);

 public:
  VMOp_Type type() const { return VMOp_ThreadDump; }
  void doit();
  bool doit_prologue();
  void doit_epilogue();
};

VM_ThreadDump继承自VM_Operation。有一点需要注意的是evaluate_at_safepoint()返回的是true,这意味着执行这个任务的时候,所有其他线程需要进入到安全点,也就是说整个JVM会被hang住。该任务的逻辑在doit()方法中:

void VM_ThreadDump::doit() {
  ResourceMark rm;

  ConcurrentLocksDump concurrent_locks(true);
  if (_with_locked_synchronizers) {
    concurrent_locks.dump_at_safepoint();
  }

  if (_num_threads == 0) {
    // Snapshot all live threads
    for (JavaThread* jt = Threads::first(); jt != NULL; jt = jt->next()) {
      if (jt->is_exiting() ||
          jt->is_hidden_from_external_view())  {
        // skip terminating threads and hidden threads
        continue;
      }
      ThreadConcurrentLocks* tcl = NULL;
      if (_with_locked_synchronizers) {
        tcl = concurrent_locks.thread_concurrent_locks(jt);
      }
      ThreadSnapshot* ts = snapshot_thread(jt, tcl);
      _result->add_thread_snapshot(ts);
    }
  } else {
    // Snapshot threads in the given _threads array
    // A dummy snapshot is created if a thread doesn't exist
    for (int i = 0; i < _num_threads; i++) {
      instanceHandle th = _threads->at(i);
      if (th() == NULL) {
        // skip if the thread doesn't exist
        // Add a dummy snapshot
        _result->add_thread_snapshot(new ThreadSnapshot());
        continue;
      }

      // Dump thread stack only if the thread is alive and not exiting
      // and not VM internal thread.
      JavaThread* jt = java_lang_Thread::thread(th());
      if (jt == NULL || /* thread not alive */
          jt->is_exiting() ||
          jt->is_hidden_from_external_view())  {
        // add a NULL snapshot if skipped
        _result->add_thread_snapshot(new ThreadSnapshot());
        continue;
      }
      ThreadConcurrentLocks* tcl = NULL;
      if (_with_locked_synchronizers) {
        tcl = concurrent_locks.thread_concurrent_locks(jt);
      }
      ThreadSnapshot* ts = snapshot_thread(jt, tcl);
      _result->add_thread_snapshot(ts);
    }
  }
}

doit方法会遍历所有线程,如果线程已经消失了,或者处于exiting状态,则会创建一个空的ThreadSnapshot放到返回值中。否则调用snapshot_thread获取对应线程的快照(堆栈信息)。

ThreadSnapshot* VM_ThreadDump::snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl) {
  ThreadSnapshot* snapshot = new ThreadSnapshot(java_thread);
  snapshot->dump_stack_at_safepoint(_max_depth, _with_locked_monitors);
  snapshot->set_concurrent_locks(tcl);
  return snapshot;
}

void ThreadSnapshot::dump_stack_at_safepoint(int max_depth, bool with_locked_monitors) {
  _stack_trace = new ThreadStackTrace(_thread, with_locked_monitors);
  _stack_trace->dump_stack_at_safepoint(max_depth);
}

void ThreadStackTrace::dump_stack_at_safepoint(int maxDepth) {
  assert(SafepointSynchronize::is_at_safepoint(), "all threads are stopped");

  if (_thread->has_last_Java_frame()) {
    RegisterMap reg_map(_thread);
    vframe* start_vf = _thread->last_java_vframe(&reg_map);
    int count = 0;
    for (vframe* f = start_vf; f; f = f->sender() ) {
      if (f->is_java_frame()) {
        javaVFrame* jvf = javaVFrame::cast(f);
        add_stack_frame(jvf);
        count++;
      } else {
        // Ignore non-Java frames
      }
      if (maxDepth > 0 && count == maxDepth) {
        // Skip frames if more than maxDepth
        break;
      }
    }
  }

  if (_with_locked_monitors) {
    // Iterate inflated monitors and find monitors locked by this thread
    // not found in the stack
    InflatedMonitorsClosure imc(_thread, this);
    ObjectSynchronizer::monitors_iterate(&imc);
  }
}

snapshot_thread调用ThreadSnapshot的dump_stack_at_safepoint方法,ThreadSnapshot调用ThreadStackTrace的dump_stack_at_safepoint方法。ThreadStackTrace则会遍历当前线程的所有栈帧(javaVFrame)将其添加到StackFrameInfo中。

StackFrameInfo::StackFrameInfo(javaVFrame* jvf, bool with_lock_info) {
  _method = jvf->method();
  _bci = jvf->bci();
  _class_holder = _method->method_holder()->klass_holder();
  _locked_monitors = NULL;
  if (with_lock_info) {
    ResourceMark rm;
    GrowableArray<MonitorInfo*>* list = jvf->locked_monitors();
    int length = list->length();
    if (length > 0) {
      _locked_monitors = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<oop>(length, true);
      for (int i = 0; i < length; i++) {
        MonitorInfo* monitor = list->at(i);
        assert(monitor->owner(), "This monitor must have an owning object");
        _locked_monitors->append(monitor->owner());
      }
    }
  }
}

StackFrameInfo主要记录了三个数据, 1、当前栈帧执行的方法 ->_method 2、对应的行数 -> _bci 3、该方法对应到类 -> _class_holder

有了StackFrameInfo我们就可以还原出对应的栈数据了。