美文网首页Android基础知识
线程生命周期及状态分析

线程生命周期及状态分析

作者: 王侦 | 来源:发表于2019-07-27 15:21 被阅读95次

1.线程的状态图

    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 <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * 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;
    }

2.sleep、wait、join和park是怎么实现阻塞的?

根据阻塞线程的相关方法分析(包括HotSpot层源码)LockSupport及HotSpot层Parker::park/unpark分析可知:

  • Object的wait/notifyAll最终调用JVM_MonitorWait/JVM_MonitorNotify
    调用ObjectMonitor::wait,最终调用ParkEvent::park ()
  • join调用wait
  • sleep调用JVM_Sleep,进而调用os::sleep,最终调用ParkEvent::park ()
  • LockSupport的park/unpark调用Parker::park/unpark

由如下的ParkEvent和Parker类可知:

  • ParkEvent -> os::PlatformEvent -> CHeapObj<mtInternal>
    Parker -> os::PlatformParker -> CHeapObj<mtInternal>
  • 其阻塞都是通过pthread_cond_t实现的

2.1 ParkEvent

class ParkEvent : public os::PlatformEvent {
  private:
    ParkEvent * FreeNext ;

    // Current association
    Thread * AssociatedWith ;
    intptr_t RawThreadIdentity ;        // LWPID etc
    volatile int Incarnation ;

    // diagnostic : keep track of last thread to wake this thread.
    // this is useful for construction of dependency graphs.
    void * LastWaker ;

  public:
    // MCS-CLH list linkage and Native Mutex/Monitor
    ParkEvent * volatile ListNext ;
    ParkEvent * volatile ListPrev ;
    volatile intptr_t OnList ;
    volatile int TState ;
    volatile int Notified ;             // for native monitor construct
    volatile int IsWaiting ;            // Enqueued on WaitSet


  private:
    static ParkEvent * volatile FreeList ;
    static volatile int ListLock ;

    // It's prudent to mark the dtor as "private"
    // ensuring that it's not visible outside the package.
    // Unfortunately gcc warns about such usage, so
    // we revert to the less desirable "protected" visibility.
    // The other compilers accept private dtors.

  protected:        // Ensure dtor is never invoked
    ~ParkEvent() { guarantee (0, "invariant") ; }

    ParkEvent() : PlatformEvent() {
       AssociatedWith = NULL ;
       FreeNext       = NULL ;
       ListNext       = NULL ;
       ListPrev       = NULL ;
       OnList         = 0 ;
       TState         = 0 ;
       Notified       = 0 ;
       IsWaiting      = 0 ;
    }

    // We use placement-new to force ParkEvent instances to be
    // aligned on 256-byte address boundaries.  This ensures that the least
    // significant byte of a ParkEvent address is always 0.

    void * operator new (size_t sz) throw();
    void operator delete (void * a) ;

  public:
    static ParkEvent * Allocate (Thread * t) ;
    static void Release (ParkEvent * e) ;
} ;

class PlatformEvent : public CHeapObj<mtInternal> {
  private:
    double CachePad [4] ;   // increase odds that _mutex is sole occupant of cache line
    volatile int _Event ;
    volatile int _nParked ;
    pthread_mutex_t _mutex  [1] ;
    pthread_cond_t  _cond   [1] ;
    double PostPad  [2] ;
    Thread * _Assoc ;

  public:       // TODO-FIXME: make dtor private
    ~PlatformEvent() { guarantee (0, "invariant") ; }

  public:
    PlatformEvent() {
      int status;
      status = pthread_cond_init (_cond, os::Linux::condAttr());
      assert_status(status == 0, status, "cond_init");
      status = pthread_mutex_init (_mutex, NULL);
      assert_status(status == 0, status, "mutex_init");
      _Event   = 0 ;
      _nParked = 0 ;
      _Assoc   = NULL ;
    }

    // Use caution with reset() and fired() -- they may require MEMBARs
    void reset() { _Event = 0 ; }
    int  fired() { return _Event; }
    void park () ;
    void unpark () ;
    int  TryPark () ;
    int  park (jlong millis) ; // relative timed-wait only
    void SetAssociation (Thread * a) { _Assoc = a ; }
} ;

2.2 Parker

class Parker : public os::PlatformParker {
private:
  volatile int _counter ;   //计数
  Parker * FreeNext ;      //指向下一个Parker
  JavaThread * AssociatedWith ; // 指向parker所属的线程。
 
public:
  Parker() : PlatformParker() {
    _counter       = 0 ;    //初始化为0
    FreeNext       = NULL ;
    AssociatedWith = NULL ;
  }
protected:
  ~Parker() { ShouldNotReachHere(); }
public:
  // For simplicity of interface with Java, all forms of park (indefinite,
  // relative, and absolute) are multiplexed into one call.
  void park(bool isAbsolute, jlong time);
  void unpark();
 
  // Lifecycle operators
  static Parker * Allocate (JavaThread * t) ;
  static void Release (Parker * e) ;
private:
  static Parker * volatile FreeList ;
  static volatile int ListLock ;
 
};
class PlatformParker : public CHeapObj<mtInternal> {
  protected:
    enum {
        REL_INDEX = 0,
        ABS_INDEX = 1
    };
    int _cur_index;  // 条件变量数组下标,which cond is in use: -1, 0, 1
    pthread_mutex_t _mutex [1] ;  //pthread互斥锁
    pthread_cond_t  _cond  [2] ; // pthread条件变量数组,一个用于相对时间,一个用于绝对时间。
 
  public:       // TODO-FIXME: make dtor private
    ~PlatformParker() { guarantee (0, "invariant") ; }
 
  public:
    PlatformParker() {
      int status;
      status = pthread_cond_init (&_cond[REL_INDEX], os::Linux::condAttr());
      assert_status(status == 0, status, "cond_init rel");
      status = pthread_cond_init (&_cond[ABS_INDEX], NULL);
      assert_status(status == 0, status, "cond_init abs");
      status = pthread_mutex_init (_mutex, NULL);
      assert_status(status == 0, status, "mutex_init");
      _cur_index = -1; // mark as unused
    }
};

3.sleep、wait、join和park对中断的响应

根据阻塞线程的相关方法分析(包括HotSpot层源码)LockSupport及HotSpot层Parker::park/unpark分析源码可知:

  • Object的wait、join、sleep当检测到中断时,会返回,并清除中断标志位
  • LockSupport.park检测到中断时也会返回,但不会清除中断标志位

3.1 Object的wait和join

void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
   Thread * const Self = THREAD ;
   assert(Self->is_Java_thread(), "Must be Java thread!");
   JavaThread *jt = (JavaThread *)THREAD;

   DeferredInitialize () ;

   // Throw IMSX or IEX.
   CHECK_OWNER();

   EventJavaMonitorWait event;

   // check for a pending interrupt
   if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
     // post monitor waited event.  Note that this is past-tense, we are done waiting.
     if (JvmtiExport::should_post_monitor_waited()) {
        // Note: 'false' parameter is passed here because the
        // wait was not timed out due to thread interrupt.
        JvmtiExport::post_monitor_waited(jt, this, false);

        // In this short circuit of the monitor wait protocol, the
        // current thread never drops ownership of the monitor and
        // never gets added to the wait queue so the current thread
        // cannot be made the successor. This means that the
        // JVMTI_EVENT_MONITOR_WAITED event handler cannot accidentally
        // consume an unpark() meant for the ParkEvent associated with
        // this ObjectMonitor.
     }
     if (event.should_commit()) {
       post_monitor_wait_event(&event, 0, millis, false);
     }
     TEVENT (Wait - Throw IEX) ;
     THROW(vmSymbols::java_lang_InterruptedException());
     return ;
   }

3.2 sleep

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

  if (millis < 0) {
    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
  }

  if (Thread::is_interrupted (THREAD, true) && !HAS_PENDING_EXCEPTION) {
    THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");
  }

  // Save current thread state and restore it at the end of this block.
  // And set new thread state to SLEEPING.
  JavaThreadSleepState jtss(thread);

3.3 LockSupport.park

void Parker::park(bool isAbsolute, jlong time) {
  // Ideally we'd do something useful while spinning, such
  // as calling unpackTime().

  // Optional fast-path check:
  // Return immediately if a permit is available.
  // We depend on Atomic::xchg() having full barrier semantics
  // since we are doing a lock-free update to _counter.
  if (Atomic::xchg(0, &_counter) > 0) return;

  Thread* thread = Thread::current();
  assert(thread->is_Java_thread(), "Must be JavaThread");
  JavaThread *jt = (JavaThread *)thread;

  // Optional optimization -- avoid state transitions if there's an interrupt pending.
  // Check interrupt before trying to wait
  if (Thread::is_interrupted(thread, false)) {
    return;
  }

相关文章

  • 我的涂床

    线程状态及生命周期

  • 线程生命周期及状态分析

    1.线程的状态图 2.sleep、wait、join和park是怎么实现阻塞的? 根据阻塞线程的相关方法分析(包括...

  • 线程的学习总结

    我打算从线程得生命周期开始总结多线程: 线程的生命周期: 新建状态:线程对象创建之后,线程进入新建状态. 就绪状态...

  • Java知识梳理六

    一、Java多线程一 1.谈谈线程的生命周期和状态转移 关于线程生命周期的不同状态,在Java 5以后,线程...

  • java多线程

    java多线程 线程类源码解读(2)-线程状态及常用方法 线程类源码解读(3)-线程中断 逐行分析AQS源码(1)...

  • java多线程基本概念(一)

    线程生命周期 说明线程工共包含5个状态: 新建状态new:调用线程构造方法创建线程后,线程进入新建状态; 就绪状态...

  • [Java][Thread需要了解的那些事之生命周期]

    1.线程生命周期 2.按图分析 当线程通过new创建了一个Thread的时候,线程就处于New状态。1.当这个Th...

  • Java基础知识(三)

    一、线程状态转化 线程状态生命周期如下: 新建状态(New):新创建了一个线程对象。 就绪状态(Runnable)...

  • Thread相关学习之二 - JavaThread&JV

    线程生命周期 JavaThread生命周期 线程生命周期就在上述的6个状态中流转,如下图: JVMTIThread...

  • 多线程-线程生命周期

    线程总共有6个生命周期状态,线程状态可以通过thread.getState()查看 线程状态是Thread.Sta...

网友评论

    本文标题:线程生命周期及状态分析

    本文链接:https://www.haomeiwen.com/subject/pvrrrctx.html