zoukankan      html  css  js  c++  java
  • LockSupport HotSpot里park/unpark的实现

    每个java线程都有一个Parker实例,Parker类是这样定义的:

    class Parker : public os::PlatformParker {
    private:
      volatile int _counter ;
      ...
    public:
      void park(bool isAbsolute, jlong time);
      void unpark();
      ...
    }
    class PlatformParker : public CHeapObj<mtInternal> {
      protected:
        pthread_mutex_t _mutex [1] ;
        pthread_cond_t  _cond  [1] ;
        ...
    }
    

    可以看到Parker类实际上用Posix的mutex,condition来实现的。

    在Parker类里的_counter字段,就是用来记录所谓的“许可”的。

    当调用park时,先尝试直接能否直接拿到“许可”,即_counter>0时,如果成功,则把_counter设置为0,并返回:

    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;
    

      如果不成功,则构造一个ThreadBlockInVM,然后检查_counter是不是>0,如果是,则把_counter设置为0,unlock mutex并返回:

      ThreadBlockInVM tbivm(jt);
      if (_counter > 0)  { // no wait needed
        _counter = 0;
        status = pthread_mutex_unlock(_mutex);
    

      否则,再判断等待的时间,然后再调用pthread_cond_wait函数等待,如果等待返回,则把_counter设置为0,unlock mutex并返回:

      if (time == 0) {
        status = pthread_cond_wait (_cond, _mutex) ;
      }
      _counter = 0 ;
      status = pthread_mutex_unlock(_mutex) ;
      assert_status(status == 0, status, "invariant") ;
      OrderAccess::fence();
    

      当unpark时,则简单多了,直接设置_counter为1,再unlock mutext返回。如果_counter之前的值是0,则还要调用pthread_cond_signal唤醒在park中等待的线程:

    void Parker::unpark() {
      int s, status ;
      status = pthread_mutex_lock(_mutex);
      assert (status == 0, "invariant") ;
      s = _counter;
      _counter = 1;
      if (s < 1) {
         if (WorkAroundNPTLTimedWaitHang) {
            status = pthread_cond_signal (_cond) ;
            assert (status == 0, "invariant") ;
            status = pthread_mutex_unlock(_mutex);
            assert (status == 0, "invariant") ;
         } else {
            status = pthread_mutex_unlock(_mutex);
            assert (status == 0, "invariant") ;
            status = pthread_cond_signal (_cond) ;
            assert (status == 0, "invariant") ;
         }
      } else {
        pthread_mutex_unlock(_mutex);
        assert (status == 0, "invariant") ;
      }
    }
    

    简而言之,是用mutex和condition保护了一个_counter的变量,当park时,这个变量置为了0,当unpark时,这个变量置为1。
    值得注意的是在park函数里,调用pthread_cond_wait时,并没有用while来判断,所以posix condition里的"Spurious wakeup"一样会传递到上层Java的代码里。

      if (time == 0) {
        status = pthread_cond_wait (_cond, _mutex) ;
      }

    这也就是为什么Java dos里提到,当下面三种情况下park函数会返回:

    • Some other thread invokes unpark with the current thread as the target; or
    • Some other thread interrupts the current thread; or
    • The call spuriously (that is, for no reason) returns.
  • 相关阅读:
    算法导论之贪心算法
    编程过程中遇到的一些细节
    c++11和c99
    面试总结(YY一面)
    python(17):字典
    python(16):元组
    python(15):练习题
    python(14):列表
    python(13):字符串
    python(12):练习题
  • 原文地址:https://www.cnblogs.com/monkey0307/p/9670704.html
Copyright © 2011-2022 走看看