结合源码记录JAVA的生命周期

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、java创建一个线程的流程

创建线程的流程

  1. 这一步很简单,大家都知道java创建线程常用的两种方法继承Thread类和实现Runnable接口,例如:
      public class ThreadDemo extends Thread{
      	    @Override
      	    public void run() {
      	        System.out.println("hello world");
      	    }
      }
      class Demo{
          public static void main(String[] args) {
              ThreadDemo threadDemo = new ThreadDemo();
              threadDemo.start();
          }
      }
    
    
    

这里我们可以看下hreadDemo.start();的源码部分
在这里插入图片描述
我们可以看到线程的启动方法是start0(),而这个start0被native()修饰,说明他是一个本地方法。下面我们下载openJDK的源码查看以下start0的调用链路是怎么样的。

下载地址:[https://hg.openjdk.org/jdk8/jdk8/jdk/file]

java类中使用了native关键字的一般会有对应的<类名>.c文件与之对应,是C语言的源码文件,主要用于实现 Java 虚拟机中的一些本地方法或者 JNI 接口。
下面我们找到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},
};

我们发下start0调用的是JVM的StartThread函数 。
下面我们来接着跟JVM_StartThread函数的源码部分,java在使用JNI(Java Native Interface)调用本地函数时,函数指针一般定义在jvm.h头文件中,代码部分如下:

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

再看jvm.cpp的源码部分
在这里插入图片描述
在这里我们可以看到源码在这里使用 new 关键字创建一个新的 JavaThread 对象,并将其构造函数的参数设置为 &thread_entry 和 sz。其中,&thread_entry 表示一个函数指针,指向一个用于执行线程的函数,sz 表示线程的栈空间大小。接下来我们需要去thread.cpp中看JavaThread的源码实现部分。
在这里插入图片描述
最终调用OS的create_thread创建线程

二、线程状态

在这里插入图片描述

下面我们根据源码和上图的状态变化,分析以下线程的几个状态。

1. 实例化线程(NEW状态)

首先我看下线程初始初始状态,当我们new Thread()实例时,我们从源码中可以看到

/* Java thread status for tools,
 * initialized to indicate thread 'not yet started'
 */
private volatile int threadStatus = 0;

在Thread.java对象中有个私有属性threadStatus,它的初始状态为0,根据上面的注释“initialized to indicate thread ‘not yet started’,翻译:已初始化以指示线程’尚未启动’”,下面我们继续追这个‘尚未启动’究竟是个什么状态。

    /**
     * Returns the state of this thread.
     * This method is designed for use in monitoring of the system state,
     * not for synchronization control.
     *
     * @return this thread's state.
     * @since 1.5
     */
    public State getState() {
        // get current thread state
        return sun.misc.VM.toThreadState(threadStatus);
    }

同样在Thread.java类中有一个getState()方法,方法里是根据threadStatus属性获取了线程状态,那么我们就可以看threadStatus=0的时候,线程是什么状态了。

    public static Thread.State toThreadState(int var0) {
        if ((var0 & 4) != 0) {
            return State.RUNNABLE;
        } else if ((var0 & 1024) != 0) {
            return State.BLOCKED;
        } else if ((var0 & 16) != 0) {
            return State.WAITING;
        } else if ((var0 & 32) != 0) {
            return State.TIMED_WAITING;
        } else if ((var0 & 2) != 0) {
            return State.TERMINATED;
        } else {
            return (var0 & 1) == 0 ? State.NEW : State.RUNNABLE;
        }
    }

threadStatus=0传入toThreadState(int)方法,会执行到else块中,0&1=0,所以线程初始状态是为NEW。

2. RUNNABLE状态

根据上面的流程图,线程在NEW状态下执行start()方法,线程变为RUNNABLE状态。

我们在上面分析start方法调用native部分的源码,这里为了方便查看我们把start方法源码贴到下方

    /**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
    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 */
            }
        }
    }

从源码可以看出,能够执行start方法的只有线程状态是NEW才可以。java的源码中在启动线程时候并没有改变线程的地方,那很有可能在start0()的本地方法中改变的状态,按着这个想法我们继续跟下start0的源码,通过上面的分析我们已经知道start0方法执行的jvm.cpp中的StartThread函数,代码如下:

JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
  JVMWrapper("JVM_StartThread");
  JavaThread *native_thread = NULL;

  // We cannot hold the Threads_lock when we throw an exception,
  // due to rank ordering issues. Example:  we might need to grab the
  // Heap_lock while we construct the exception.
  bool throw_illegal_thread_state = false;

  // We must release the Threads_lock before we can post a jvmti event
  // in Thread::start.
  {
    // Ensure that the C++ Thread and OSThread structures aren't freed before
    // we operate.
    MutexLocker mu(Threads_lock);

    // Since JDK 5 the java.lang.Thread threadStatus is used to prevent
    // re-starting an already started thread, so we should usually find
    // that the JavaThread is null. However for a JNI attached thread
    // there is a small window between the Thread object being created
    // (with its JavaThread set) and the update to its threadStatus, so we
    // have to check for this
    if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) {
      throw_illegal_thread_state = true;
    } else {
      // We could also check the stillborn flag to see if this thread was already stopped, but
      // for historical reasons we let the thread detect that itself when it starts running

      jlong size =
             java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));
      // Allocate the C++ Thread structure and create the native thread.  The
      // stack size retrieved from java is signed, but the constructor takes
      // size_t (an unsigned type), so avoid passing negative values which would
      // result in really large stacks.
      size_t sz = size > 0 ? (size_t) size : 0;
      native_thread = new JavaThread(&thread_entry, sz);

      // At this point it may be possible that no osthread was created for the
      // JavaThread due to lack of memory. Check for this situation and throw
      // an exception if necessary. Eventually we may want to change this so
      // that we only grab the lock if the thread was created successfully -
      // then we can also do this check and throw the exception in the
      // JavaThread constructor.
      if (native_thread->osthread() != NULL) {
        // Note: the current thread is not being used within "prepare".
        native_thread->prepare(jthread);
      }
    }
  }

  if (throw_illegal_thread_state) {
    THROW(vmSymbols::java_lang_IllegalThreadStateException());
  }

  assert(native_thread != NULL, "Starting null thread?");

  if (native_thread->osthread() == NULL) {
    // No one should hold a reference to the 'native_thread'.
    delete native_thread;
    if (JvmtiExport::should_post_resource_exhausted()) {
      JvmtiExport::post_resource_exhausted(
        JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_THREADS,
        "unable to create new native thread");
    }
    THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
              "unable to create new native thread");
  }

#if INCLUDE_JFR
  if (JfrRecorder::is_recording() && EventThreadStart::is_enabled() &&
      EventThreadStart::is_stacktrace_enabled()) {
    JfrThreadLocal* tl = native_thread->jfr_thread_local();
    // skip Thread.start() and Thread.start0()
    tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(thread, 2));
  }
#endif

  Thread::start(native_thread);

JVM_END

上面代码可以看到启动线程执行的是Thread::start(native_thread);这行代码,下面我们去thread.cpp文件找到这个start函数源码,看看干了些什么事情呢?

void Thread::start(Thread* thread) {
  trace("start", thread);
  // Start is different from resume in that its safety is guaranteed by context or
  // being called from a Java method synchronized on the Thread object.
  if (!DisableStartThread) {
    if (thread->is_Java_thread()) {
      // Initialize the thread state to RUNNABLE before starting this thread.
      // Can not set it after the thread started because we do not know the
      // exact thread state at that time. It could be in MONITOR_WAIT or
      // in SLEEPING or some other state.
      java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),
                                          java_lang_Thread::RUNNABLE);
    }
    os::start_thread(thread);
  }
}

在这里我们可以看到,它把线程状态改为了枚举RUNNABLE(与java线程对象状态对应关系请参考:简述java线程类Thread的状态获取逻辑),并且在系统中开启了线程。

线程的RUNNING和READY状态
其实在java中RUNNING和READY两个状态都属于RUNNABLE状态,只是这两个状态是系统底层的实现,对JVM是不可见的。

  • RUNNING 状态:表示当前线程正在运行,也就是当前线程正在执行其代码逻辑。
  • READY 状态:表示线程已经准备好运行,但是还没有得到 CPU 时间片。这通常是因为系统中有其他线程正在执行,所以当前线程需要等待其他线程执行完毕并释放 CPU 时间片后才能执行。

3. BLOCKED状态

使线程变更为BLOCKED状态的有几个场景,下面一一列举看下:

synchronized

在Java中,synchronized方法或代码块是用来保证多个线程之间的同步的机制之一。当一个线程进入synchronized方法或代码块时,它会尝试获取该对象的锁。如果锁已经被其他线程占用,则当前线程会进入BLOCKED状态,直到其他线程释放该对象的锁。

具体来说,当一个线程进入synchronized方法或代码块时,它会首先尝试获取该对象的监视器锁(也称为内部锁或对象锁)。如果该对象的锁已经被其他线程占用,则当前线程会被阻塞并进入BLOCKED状态,等待其他线程释放该锁。

当其他线程释放该对象的锁时,处于BLOCKED状态的线程会重新尝试获取锁并继续执行。如果当前线程成功获取到锁,则它会进入RUNNABLE状态,继续执行synchronized方法或代码块中的代码。如果当前线程无法获取到锁,则它会继续保持BLOCKED状态,直到下一次有机会获取到该锁。

那么我们就来关注一下JVM的源码ObjectMonitor::enter(获取监视器锁)的源码,看下是否有处理线程状态的相关代码

void ATTR ObjectMonitor::enter(TRAPS) {
  // The following code is ordered to check the most common cases first
  // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
  Thread * const Self = THREAD ;
  void * cur ;

  cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
  if (cur == NULL) {
     // Either ASSERT _recursions == 0 or explicitly set _recursions = 0.
     assert (_recursions == 0   , "invariant") ;
     assert (_owner      == Self, "invariant") ;
     // CONSIDER: set or assert OwnerIsThread == 1
     return ;
  }

  if (cur == Self) {
     // TODO-FIXME: check for integer overflow!  BUGID 6557169.
     _recursions ++ ;
     return ;
  }

  if (Self->is_lock_owned ((address)cur)) {
    assert (_recursions == 0, "internal state error");
    _recursions = 1 ;
    // Commute owner from a thread-specific on-stack BasicLockObject address to
    // a full-fledged "Thread *".
    _owner = Self ;
    OwnerIsThread = 1 ;
    return ;
  }

  // We've encountered genuine contention.
  assert (Self->_Stalled == 0, "invariant") ;
  Self->_Stalled = intptr_t(this) ;

  // Try one round of spinning *before* enqueueing Self
  // and before going through the awkward and expensive state
  // transitions.  The following spin is strictly optional ...
  // Note that if we acquire the monitor from an initial spin
  // we forgo posting JVMTI events and firing DTRACE probes.
  if (Knob_SpinEarly && TrySpin (Self) > 0) {
     assert (_owner == Self      , "invariant") ;
     assert (_recursions == 0    , "invariant") ;
     assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
     Self->_Stalled = 0 ;
     return ;
  }

  assert (_owner != Self          , "invariant") ;
  assert (_succ  != Self          , "invariant") ;
  assert (Self->is_Java_thread()  , "invariant") ;
  JavaThread * jt = (JavaThread *) Self ;
  assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ;
  assert (jt->thread_state() != _thread_blocked   , "invariant") ;
  assert (this->object() != NULL  , "invariant") ;
  assert (_count >= 0, "invariant") ;

  // Prevent deflation at STW-time.  See deflate_idle_monitors() and is_busy().
  // Ensure the object-monitor relationship remains stable while there's contention.
  Atomic::inc_ptr(&_count);

  JFR_ONLY(JfrConditionalFlushWithStacktrace<EventJavaMonitorEnter> flush(jt);)
  EventJavaMonitorEnter event;
  if (event.should_commit()) {
    event.set_monitorClass(((oop)this->object())->klass());
    event.set_address((uintptr_t)(this->object_addr()));
  }

  { // Change java thread status to indicate blocked on monitor enter.
    JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);

    Self->set_current_pending_monitor(this);

    DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt);
    if (JvmtiExport::should_post_monitor_contended_enter()) {
      JvmtiExport::post_monitor_contended_enter(jt, this);

      // The current thread does not yet own the monitor and does not
      // yet appear on any queues that would get it made the successor.
      // This means that the JVMTI_EVENT_MONITOR_CONTENDED_ENTER event
      // handler cannot accidentally consume an unpark() meant for the
      // ParkEvent associated with this ObjectMonitor.
    }

    OSThreadContendState osts(Self->osthread());
    ThreadBlockInVM tbivm(jt);

    // TODO-FIXME: change the following for(;;) loop to straight-line code.
    for (;;) {
      jt->set_suspend_equivalent();
      // cleared by handle_special_suspend_equivalent_condition()
      // or java_suspend_self()

      EnterI (THREAD) ;

      if (!ExitSuspendEquivalent(jt)) break ;

      //
      // We have acquired the contended monitor, but while we were
      // waiting another thread suspended us. We don't want to enter
      // the monitor while suspended because that would surprise the
      // thread that suspended us.
      //
          _recursions = 0 ;
      _succ = NULL ;
      exit (false, Self) ;

      jt->java_suspend_self();
    }
    Self->set_current_pending_monitor(NULL);

    // We cleared the pending monitor info since we've just gotten past
    // the enter-check-for-suspend dance and we now own the monitor free
    // and clear, i.e., it is no longer pending. The ThreadBlockInVM
    // destructor can go to a safepoint at the end of this block. If we
    // do a thread dump during that safepoint, then this thread will show
    // as having "-locked" the monitor, but the OS and java.lang.Thread
    // states will still report that the thread is blocked trying to
    // acquire it.
  }

  Atomic::dec_ptr(&_count);
  assert (_count >= 0, "invariant") ;
  Self->_Stalled = 0 ;

  // Must either set _recursions = 0 or ASSERT _recursions == 0.
  assert (_recursions == 0     , "invariant") ;
  assert (_owner == Self       , "invariant") ;
  assert (_succ  != Self       , "invariant") ;
  assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;

  // The thread -- now the owner -- is back in vm mode.
  // Report the glorious news via TI,DTrace and jvmstat.
  // The probe effect is non-trivial.  All the reportage occurs
  // while we hold the monitor, increasing the length of the critical
  // section.  Amdahl's parallel speedup law comes vividly into play.
  //
  // Another option might be to aggregate the events (thread local or
  // per-monitor aggregation) and defer reporting until a more opportune
  // time -- such as next time some thread encounters contention but has
  // yet to acquire the lock.  While spinning that thread could
  // spinning we could increment JVMStat counters, etc.

  DTRACE_MONITOR_PROBE(contended__entered, this, object(), jt);
  if (JvmtiExport::should_post_monitor_contended_entered()) {
    JvmtiExport::post_monitor_contended_entered(jt, this);

    // The current thread already owns the monitor and is not going to
    // call park() for the remainder of the monitor enter protocol. So
    // it doesn't matter if the JVMTI_EVENT_MONITOR_CONTENDED_ENTERED
    // event handler consumed an unpark() issued by the thread that
    // just exited the monitor.
  }

  if (event.should_commit()) {
    event.set_previousOwner((uintptr_t)_previous_owner_tid);
    event.commit();
  }

  if (ObjectMonitor::_sync_ContendedLockAttempts != NULL) {
     ObjectMonitor::_sync_ContendedLockAttempts->inc() ;
  }
}

我们看到有一行JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);这个代码,如下图,在监视器锁被其他线程占用是会最终执行这行代码,而根据注释我们也能看出来,这里要把这个java线程的状态变为blocked。
在这里插入图片描述
下面再看下JavaThreadBlockedOnMonitorEnterState这个类的代码

// Change status to blocked on (re-)entering a synchronization block
class JavaThreadBlockedOnMonitorEnterState : public JavaThreadStatusChanger {
 private:
  ThreadStatistics* _stat;
  bool _active;

  static bool contended_enter_begin(JavaThread *java_thread) {
    set_thread_status(java_thread, java_lang_Thread::BLOCKED_ON_MONITOR_ENTER);
    ThreadStatistics* stat = java_thread->get_thread_stat();
    stat->contended_enter();
    bool active = ThreadService::is_thread_monitoring_contention();
    if (active) {
      stat->contended_enter_begin();
    }
    return active;
  }

 public:
  // java_thread is waiting thread being blocked on monitor reenter.
  // Current thread is the notifying thread which holds the monitor.
  static bool wait_reenter_begin(JavaThread *java_thread, ObjectMonitor *obj_m) {
    assert((java_thread != NULL), "Java thread should not be null here");
    bool active = false;
    if (is_alive(java_thread) && ServiceUtil::visible_oop((oop)obj_m->object())) {
      active = contended_enter_begin(java_thread);
    }
    return active;
  }

  static void wait_reenter_end(JavaThread *java_thread, bool active) {
    if (active) {
      java_thread->get_thread_stat()->contended_enter_end();
    }
    set_thread_status(java_thread, java_lang_Thread::RUNNABLE);
  }

  JavaThreadBlockedOnMonitorEnterState(JavaThread *java_thread, ObjectMonitor *obj_m) :
    _stat(NULL), _active(false), JavaThreadStatusChanger(java_thread) {
    assert((java_thread != NULL), "Java thread should not be null here");
    // Change thread status and collect contended enter stats for monitor contended
    // enter done for external java world objects and it is contended. All other cases
    // like for vm internal objects and for external objects which are not contended
    // thread status is not changed and contended enter stat is not collected.
    _active = false;
    if (is_alive() && ServiceUtil::visible_oop((oop)obj_m->object()) && obj_m->contentions() > 0) {
      _stat = java_thread->get_thread_stat();
      _active = contended_enter_begin(java_thread);
    }
  }

  ~JavaThreadBlockedOnMonitorEnterState() {
    if (_active) {
      _stat->contended_enter_end();
    }
  }
};

参考上面的代码,在实例化JavaThreadBlockedOnMonitorEnterState类的时候,有个判断逻辑:if (is_alive() && ServiceUtil::visible_oop((oop)obj_m->object()) && obj_m->contentions() > 0),而这三个判断条件分别是:
is_alive():检查线程是否处于活动状态
ServiceUtil::visible_oop((oop)obj_m->object()):检查锁对象是否可见,即锁对象是否还存在。
obj_m->contentions() > 0:该条件检查锁对象是否有竞争。
因为没有获取到监视器锁的线程这三个条件应该都是满足的,所以最终在contended_enter_begin(java_thread)方法中的set_thread_status(java_thread, java_lang_Thread::BLOCKED_ON_MONITOR_ENTER);修改的线程状态为BLOCKED。

Object.wait()

Object类中wait()方法的调用链路:wait() -> wait(0) -> native void wait(long timeout),最终调用的是本地方法wait。
下面我们看下JDK中wait(long timeout)的实现

//Object.c
static JNINativeMethod methods[] = {
    {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
    {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
    {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
    {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
    {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
};


//jvm.h
JNIEXPORT void JNICALL
JVM_MonitorWait(JNIEnv *env, jobject obj, jlong ms);


//jvm.cpp
JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
  JVMWrapper("JVM_MonitorWait");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  JavaThreadInObjectWaitState jtiows(thread, ms != 0);
  if (JvmtiExport::should_post_monitor_wait()) {
    JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);

    // The current thread already owns the monitor and it has not yet
    // been added to the wait queue so the current thread cannot be
    // made the successor. This means that the JVMTI_EVENT_MONITOR_WAIT
    // event handler cannot accidentally consume an unpark() meant for
    // the ParkEvent associated with this ObjectMonitor.
  }
  ObjectSynchronizer::wait(obj, ms, CHECK);
JVM_END


//threadService.hpp
class JavaThreadInObjectWaitState : public JavaThreadStatusChanger {
 private:
  ThreadStatistics* _stat;
  bool _active;

 public:
  JavaThreadInObjectWaitState(JavaThread *java_thread, bool timed) :
    JavaThreadStatusChanger(java_thread,
                            timed ? java_lang_Thread::IN_OBJECT_WAIT_TIMED : java_lang_Thread::IN_OBJECT_WAIT) {
    if (is_alive()) {
      _stat = java_thread->get_thread_stat();
      _active = ThreadService::is_thread_monitoring_contention();
      _stat->monitor_wait();
      if (_active) {
        _stat->monitor_wait_begin();
      }
    } else {
      _active = false;
    }
  }

  ~JavaThreadInObjectWaitState() {
    if (_active) {
      _stat->monitor_wait_end();
    }
  }
};

线程被调用了 Object.wait() 方法,最终我们在JavaThreadInObjectWaitState对象中看到,这里把线程状态修改成了IN_OBJECT_WAIT,此状态对应java的线程状态为WAITING。那线程是怎么变成BLOCKED状态呢?它发生在线程执行 object.wait() 方法时,线程会释放该对象的锁,等待其他线程获得该对象的锁并执行完相应的 synchronized 块,当其他线程执行完 synchronized 块并释放了该对象的锁后,当前线程就会被唤醒,此时其状态会变为 BLOCKED;
线程被唤醒,那么我们看下notify()或者notifyAll()方法。这里我们追下notifyAll()源码。notifyAll()在Object类中直接调用的native方法,我们直接看JDK中的代码

//jvm.cpp
JVM_ENTRY(void, JVM_MonitorNotifyAll(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_MonitorNotifyAll");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  ObjectSynchronizer::notifyall(obj, CHECK);
JVM_END

//synchronizer.cpp
void ObjectSynchronizer::notifyall(Handle obj, TRAPS) {
  if (UseBiasedLocking) {
    BiasedLocking::revoke_and_rebias(obj, false, THREAD);
    assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
  }

  markOop mark = obj->mark();
  if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
    return;
  }
  ObjectSynchronizer::inflate(THREAD,
                              obj(),
                              inflate_cause_notify)->notifyAll(THREAD);
}


//objectMonitor.cpp
void ObjectMonitor::notifyAll(TRAPS) {
  
  //.....省略了一堆代码

     if (Policy < 4) {
       iterator->wait_reenter_begin(this);
     }
  //.....省略了一堆代码
}

void ObjectWaiter::wait_reenter_begin(ObjectMonitor *mon) {
  JavaThread *jt = (JavaThread *)this->_thread;
  _active = JavaThreadBlockedOnMonitorEnterState::wait_reenter_begin(jt, mon);
}

JavaThreadBlockedOnMonitorEnterState对象的wait_reenter_begin方法,我们在讲BLOCKED状态时看到了源码,它会调用contended_enter_begin方法,而该方法干的第一件事就是把线程状态置为BLOCKED_ON_MONITOR_ENTER。

4. WAITING状态

因为上面讲BLOCKED状态已经说到了WAITING的状态变更,这里就不再叙述了。

5. TIMED_WAITING状态

下面我跟下Thread.sleep(long)的方法,从Thread类中看到sleep(long millis)也是一个本地方法,下面我们来看下相关代码

//Thread.c
{"sleep",            "(J)V",       (void *)&JVM_Sleep}

//jvm.cpp
JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
  JVMWrapper("JVM_Sleep");

  //...省略部分代码
  
  JavaThreadSleepState jtss(thread);

  //...省略部分代码
JVM_END

//threadService.hpp
class JavaThreadSleepState : public JavaThreadStatusChanger {
 private:
  ThreadStatistics* _stat;
  bool _active;
 public:
  JavaThreadSleepState(JavaThread *java_thread) :
    JavaThreadStatusChanger(java_thread, java_lang_Thread::SLEEPING) {
    if (is_alive()) {
      _stat = java_thread->get_thread_stat();
      _active = ThreadService::is_thread_monitoring_contention();
      _stat->thread_sleep();
      if (_active) {
        _stat->thread_sleep_begin();
      }
    } else {
      _active = false;
    }
  }

  ~JavaThreadSleepState() {
    if (_active) {
      _stat->thread_sleep_end();
    }
  }
};

以上代码最终JavaThreadStatusChanger(java_thread, java_lang_Thread::SLEEPING)这行代码把线程的状态修改成了SLEEPING,而SLEEPING枚举对应的值经过计算对应的就是java Thread类中的TIMED_WAITING状态。

5. TERMINATED状态

Java 线程在终止时会将其状态置为 TERMINATED,具体到源码实现上,线程执行结束后,会调用 Thread::exit() 方法。
Thread 类并没有显式调用 exit() 方法,因为 exit() 方法是 Thread 类的一个私有方法,只能在 Thread 类内部被调用。在 Thread 类中,exit() 方法是被 JVM 虚拟机在特定的时机调用的,例如当 run() 方法执行完成后,JVM 会自动调用 exit() 方法将线程状态置为 TERMINATED。除此之外,还有其他情况也可能会触发 exit() 方法的调用,例如线程被中断或者发生异常等情况。
下面我们看部分相关源码

//thread.cpp
void JavaThread::run() {

  // ...省略部分代码
  
  // We call another function to do the rest so we are sure that the stack addresses used
  // from there will be lower than the stack base just computed
  thread_main_inner();

}

void JavaThread::thread_main_inner() {
  assert(JavaThread::current() == this, "sanity check");
  assert(this->threadObj() != NULL, "just checking");

  // Execute thread entry point unless this thread has a pending exception
  // or has been stopped before starting.
  // Note: Due to JVM_StopThread we can have pending exceptions already!
  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);
    this->entry_point()(this, this);
  }

  DTRACE_THREAD_PROBE(stop, this);

  this->exit(false);
  delete this;
}

void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
	//...省略部分代码
	ensure_join(this);
}

static void ensure_join(JavaThread* thread) {
  // ...省略部分代码
  // Thread is exiting. So set thread_status field in  java.lang.Thread class to TERMINATED.
  java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
  // ...省略部分代码
}

最终run方法执行完成,JVM会把线程状态置为TERMINATED

总结

新建(New):当线程对象被创建时,它处于新建状态。此时,它还没有被启动,即还没有调用start()方法。
可运行(Runnable):线程被启动后,它进入可运行状态。此时,线程正在运行,或者在等待系统资源(如CPU)分配给它,以便开始运行。
阻塞(Blocked):线程可能会被阻塞,即暂时停止运行。当线程等待某个监视器锁时,它将进入阻塞状态。此时,线程将暂停运行,直到另一个线程释放锁。
等待(Waiting):线程在等待某个条件的出现时,将进入等待状态。当线程调用wait()、join()、park()等方法时,它将进入等待状态。此时,线程将暂停运行,直到满足特定条件。
计时等待(Timed Waiting):线程可以通过调用带有时间参数的wait()、join()、sleep()、parkNanos()、parkUntil()等方法进入计时等待状态。此时,线程将暂停运行一段时间,直到等待时间结束或者满足特定条件。
终止(Terminated):线程的run()方法执行完毕后,线程将进入终止状态。此时,线程将不再运行,并且不可再次启动。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值