前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java线程的状态分析

Java线程的状态分析

作者头像
KINGYT
发布2023-03-15 13:45:28
5910
发布2023-03-15 13:45:28
举报

本文将从源码角度分析Java线程的各种状态以及进入该状态所对应的操作。OpenJDK版本

代码语言:javascript
复制
➜  jdk hg id
76072a077ee1+ jdk-11+28

首先用jstack命令看下Java线程的状态及堆栈信息(删减了无用内容)

代码语言:javascript
复制
"TEST_while(true)" #12 ... runnable  [0x00007f22439e2000]
   java.lang.Thread.State: RUNNABLE
 at java.lang.Thread.yield(java.base@11/Native Method)
 at test.ThreadStateTest$1.run(modules/ThreadStateTest.java:13)


"TEST_Thread.sleep(n)" #13 ... waiting on condition  [0x00007f22438e1000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
 at java.lang.Thread.sleep(java.base@11/Native Method)
 at test.ThreadStateTest$2.run(modules/ThreadStateTest.java:22)


"TEST_Object.wait()" #14 ... in Object.wait()  [0x00007f22437e0000]
   java.lang.Thread.State: WAITING (on object monitor)
 at java.lang.Object.wait(java.base@11/Native Method)
 - waiting on <0x0000000718aeb7a0> (a test.ThreadStateTest$3)
 at java.lang.Object.wait(java.base@11/Object.java:328)
 at test.ThreadStateTest$3.run(modules/ThreadStateTest.java:34)
 - waiting to re-lock in wait() <...> (a test.ThreadStateTest$3)


"TEST_Object.wait(n)" #15 ... in Object.wait()  [0x00007f22436df000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
 at java.lang.Object.wait(java.base@11/Native Method)
 - waiting on <0x0000000718aec768> (a test.ThreadStateTest$4)
 at test.ThreadStateTest$4.run(modules/ThreadStateTest.java:47)
 - waiting to re-lock in wait() <...> (a test.ThreadStateTest$4)


"TEST_LockSupport.park()" #16 ... waiting on condition  [0x00007f22435de000]
   java.lang.Thread.State: WAITING (parking)
 at jdk.internal.misc.Unsafe.park(java.base@11/Native Method)
 at java.util.concurrent.locks.LockSupport.park(...)
 at test.ThreadStateTest$5.run(modules/ThreadStateTest.java:58)


"TEST_LockSupport.parkNanos(n)" #17 ... waiting on condition  [...]
   java.lang.Thread.State: TIMED_WAITING (parking)
 at jdk.internal.misc.Unsafe.park(java.base@11/Native Method)
 at java.util.concurrent.locks.LockSupport.parkNanos(...)
 at test.ThreadStateTest$6.run(modules/ThreadStateTest.java:65)


"TEST_synchronized" #18 ... waiting for monitor entry  [0x00007f22433dc000]
   java.lang.Thread.State: BLOCKED (on object monitor)
 at test.ThreadStateTest$7.run(modules/ThreadStateTest.java:74)
 - waiting to lock <...> (a java.lang.Class for java.lang.Object)

由上我们可以看到,Java线程的状态可以为RUNNABLE、WAITING、TIMED_WAITING和BLOCKED等,而通过其堆栈信息,我们又可以大致推测出是何种操作导致的这种状态。

不过,细心的朋友在看上面的堆栈信息时肯定会有很多困惑,比如,同样是调用了Object.wait方法,为什么线程#14进入的是WAITING状态,而线程#15进入的是TIMED_WAITING状态呢?

下面我们还是通过源码角度对此做个全面的分析。

首先,找到jstack命令对应的JVM源码

C++文件src/hotspot/share/services/attachListener.cpp

代码语言:javascript
复制
static jint thread_dump(AttachOperation* op, outputStream* out) {
  ...
  // thread stacks
  VM_PrintThreads op1(out, print_concurrent_locks, print_extended_info);
  VMThread::execute(&op1);


  // JNI global handles
  VM_PrintJNI op2(out);
  VMThread::execute(&op2);


  // Deadlock detection
  VM_FindDeadlocks op3(out);
  VMThread::execute(&op3);


  return JNI_OK;
}

因为我们关心的是 thread stacks 部分,所以看下VM_PrintThreads对应的操作

C++文件src/hotspot/share/runtime/vm_operations.cpp

代码语言:javascript
复制
void VM_PrintThreads::doit() {
  Threads::print_on(_out, true, false, _print_concurrent_locks, _print_extended_info);
}

再看下Threads::print_on方法

C++文件src/hotspot/share/runtime/thread.cpp

代码语言:javascript
复制
// Threads::print_on() is called at safepoint by VM_PrintThreads operation.
void Threads::print_on(outputStream* st, bool print_stacks,
                       bool internal_format, bool print_concurrent_locks,
                       bool print_extended_info) {
  ...
  ALL_JAVA_THREADS(p) {
    ResourceMark rm;
    p->print_on(st, print_extended_info);
    if (print_stacks) {
      if (internal_format) {
        p->trace_stack();
      } else {
        p->print_stack_on(st);
      }
    }
    ...
  }
  ...
}

重点看下Java线程的print_on方法

C++文件src/hotspot/share/runtime/thread.cpp

代码语言:javascript
复制
// Called by Threads::print() for VM_PrintThreads operation
void JavaThread::print_on(outputStream *st, bool print_extended_info) const {
  ...
  st->print_raw(get_thread_name());
  ...
  if (thread_oop != NULL) {
    st->print_cr("   java.lang.Thread.State: %s", java_lang_Thread::thread_status_name(thread_oop));
  }
  ...
}

在这里我们找到了输出线程状态的地方。我们再看下java_lang_Thread::thread_status_name方法

C++文件src/hotspot/share/classfile/javaClasses.cpp

代码语言:javascript
复制
const char* java_lang_Thread::thread_status_name(oop java_thread) {
  assert(_thread_status_offset != 0, "Must have thread status");
  ThreadStatus status = (java_lang_Thread::ThreadStatus)java_thread->int_field(_thread_status_offset);
  switch (status) {
    case NEW                      : return "NEW";
    case RUNNABLE                 : return "RUNNABLE";
    case SLEEPING                 : return "TIMED_WAITING (sleeping)";
    case IN_OBJECT_WAIT           : return "WAITING (on object monitor)";
    case IN_OBJECT_WAIT_TIMED     : return "TIMED_WAITING (on object monitor)";
    case PARKED                   : return "WAITING (parking)";
    case PARKED_TIMED             : return "TIMED_WAITING (parking)";
    case BLOCKED_ON_MONITOR_ENTER : return "BLOCKED (on object monitor)";
    case TERMINATED               : return "TERMINATED";
    default                       : return "UNKNOWN";
  };
}

在该方法里,我们可以看到Java线程的所有可能状态,以及各种状态对应到jstack里会输出的名字。

那这些状态又是在哪里设置的呢?

JVM中有一个C++类叫JavaThreadStatusChanger,该类及其子类就是用来修改Java线程状态的,我们看下都有哪些子类

代码语言:javascript
复制
File: src/hotspot/share/services/threadService.hpp
469:34:class JavaThreadInObjectWaitState : public JavaThreadStatusChanger {
498:28:class JavaThreadParkedState : public JavaThreadStatusChanger {
527:43:class JavaThreadBlockedOnMonitorEnterState : public JavaThreadStatusChanger {
584:27:class JavaThreadSleepState : public JavaThreadStatusChanger {

由上我们可以看到,一共有四个子类负责修改Java线程的状态。

但又是什么操作导致这些类对Java线程的状态进行修改的呢?下面我们以JavaThreadInObjectWaitState类举例说明下。首先看下这个类

C++文件src/hotspot/share/services/threadService.hpp

代码语言:javascript
复制
// Change status to waiting on an object  (timed or indefinite)
class JavaThreadInObjectWaitState : public JavaThreadStatusChanger {
 ...
 public:
  JavaThreadInObjectWaitState(JavaThread *java_thread, bool timed) :
    JavaThreadStatusChanger(java_thread,
                            timed ? java_lang_Thread::IN_OBJECT_WAIT_TIMED : java_lang_Thread::IN_OBJECT_WAIT) {
    ...
  }
  ...
};

由上可见,该类会根据timed参数来决定是把Java线程修改为IN_OBJECT_WAIT_TIMED状态还是IN_OBJECT_WAIT状态。我们再来看下这个类是在哪里创建的,以及timed参数又是怎么传入的

C++文件src/hotspot/share/prims/jvm.cpp

代码语言:javascript
复制
JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
  ...
  JavaThreadInObjectWaitState jtiows(thread, ms != 0);
  ...
  ObjectSynchronizer::wait(obj, ms, CHECK);
JVM_END

由上可见,JavaThreadInObjectWaitState类的是由JVM_MonitorWait方法创建的,且timed参数是由ms是否等于0决定的。如果ms等于0,Java线程就会被JavaThreadInObjectWaitState类修改为IN_OBJECT_WAIT状态,如果不等于0,就会被修改为IN_OBJECT_WAIT_TIMED状态。

我们再来看下是谁调用的JVM_MonitorWait方法。

C文件src/java.base/share/native/libjava/Object.c

代码语言:javascript
复制
static JNINativeMethod methods[] = {
    ...
    {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
    {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
    {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
    ...
};

由上可以看到,是Java类java.lang.Object中的Object.wait这个native方法。

至此,我们就明白了,当我们调用Object.wait方法时,会切换Java线程的状态。如果调用该方法时传入的参数为0,Java线程就会被切换成IN_OBJECT_WAIT状态,对应jstack的输出为”WAITING (on object monitor)”。如果传入的参数大于0,Java线程就会被切换成IN_OBJECT_WAIT_TIMED状态,对应的jstack输出就是 “TIMED_WAITING (on object monitor)”。

其他三个子类也是类似,在此就不一一赘述了。

下面我们总结下,jstack命令可能输出线程状态以及导致这种状态的操作是什么。

jstack输出 | 对应的操作 ------------------------------------------------------------------------- NEW | 创建Thread对象 RUNNABLE | 调用Thread.start方法 TERMINATED | 销毁Thread对象 TIMED_WAITING (sleeping) | 调用Thread.sleep方法 WAITING (on object monitor) | 调用Object.wait方法,参数为0 TIMED_WAITING (on object monitor) | 调用Object.wait方法,参数大于0 WAITING (parking) | 调用Unsafe.park方法,参数为0 | (通常由LockSupport.park系列方法触发) TIMED_WAITING (parking) | 调用Unsafe.park方法,参数大于0 | (通常由LockSupport.park系列方法触发) BLOCKED (on object monitor) | 等待进入synchronize代码块 | (其他线程正在执行该代码块)

其实Java类java.lang.Thread.State的Javadoc对此也有较为详细的描述,只是其状态和jstack中的状态不是一一对应的,所以我们一开始并没有提到,这里也顺便看下吧。

代码语言:javascript
复制
public enum State {
    /**
     * Thread state for a thread which has not yet started.
     */
    NEW,


    /**
     * Thread state for a runnable thread.  A thread in the runnable
     * state is executing in the Java virtual machine but it may
     * be waiting for other resources from the operating system
     * such as processor.
     */
    RUNNABLE,


    /**
     * Thread state for a thread blocked waiting for a monitor lock.
     * A thread in the blocked state is waiting for a monitor lock
     * to enter a synchronized block/method or
     * reenter a synchronized block/method after calling
     * {@link Object#wait() Object.wait}.
     */
    BLOCKED,


    /**
     * Thread state for a waiting thread.
     * A thread is in the waiting state due to calling one of the
     * following methods:
     * <ul>
     *   <li>{@link Object#wait() Object.wait} with no timeout</li>
     *   <li>{@link #join() Thread.join} with no timeout</li>
     *   <li>{@link LockSupport#park() LockSupport.park}</li>
     * </ul>
     *
     * <p>A thread in the waiting state is waiting for another thread to
     * perform a particular action.
     *
     * For example, a thread that has called {@code Object.wait()}
     * on an object is waiting for another thread to call
     * {@code Object.notify()} or {@code Object.notifyAll()} on
     * that object. A thread that has called {@code Thread.join()}
     * is waiting for a specified thread to terminate.
     */
    WAITING,


    /**
     * Thread state for a waiting thread with a specified waiting time.
     * A thread is in the timed waiting state due to calling one of
     * the following methods with a specified positive waiting time:
     * <ul>
     *   <li>{@link #sleep Thread.sleep}</li>
     *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
     *   <li>{@link #join(long) Thread.join} with timeout</li>
     *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
     *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
     * </ul>
     */
    TIMED_WAITING,


    /**
     * Thread state for a terminated thread.
     * The thread has completed execution.
     */
    TERMINATED;
}

最后,附上本文中用于jstack命令的Java测试代码

代码语言:javascript
复制
// RUNNABLE
new Thread("TEST_while(true)") {
  @Override
  public void run() {
    while (true) {
      Thread.yield();
    }
  }
}.start();


// TIMED_WAITING (sleeping)
new Thread("TEST_Thread.sleep(n)") {
  @Override
  public void run() {
    try {
      Thread.sleep(Integer.MAX_VALUE);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}.start();


// WAITING (on object monitor)
new Thread("TEST_Object.wait()") {
  @Override
  public void run() {
    try {
      synchronized (this) {
        wait();
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}.start();


// TIMED_WAITING (on object monitor)
new Thread("TEST_Object.wait(n)") {
  @Override
  public void run() {
    try {
      synchronized (this) {
        wait(Integer.MAX_VALUE);
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}.start();


// WAITING (parking)
new Thread("TEST_LockSupport.park()") {
  @Override
  public void run() {
    LockSupport.park();
  }
}.start();


// TIMED_WAITING (parking)
new Thread("TEST_LockSupport.parkNanos(n)") {
  @Override
  public void run() {
    LockSupport.parkNanos(Long.MAX_VALUE);
  }
}.start();


// BLOCKED (on object monitor)
synchronized (Object.class) {
  new Thread("TEST_synchronized") {
    @Override
    public void run() {
      synchronized (Object.class) {
        System.out.println("Should not reach here!");
      }
    }
  }.start();


  try {
    Thread.sleep(Integer.MAX_VALUE);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-01-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 卯时卯刻 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档