zoukankan      html  css  js  c++  java
  • LockSupport

     
    concurrent包是基于AQS (AbstractQueuedSynchronizer)框架的,AQS框架借助于两个类:
    • Unsafe(提供CAS操作)
    • LockSupport(提供park/unpark操作,底层仍然调用是Unsafe类的park/unpark方法)
    因此,LockSupport非常重要。先看一下park和unpark方法怎么用的吧。
     
    示例:
    public static void main(String[] args) throws Exception {
    
        Thread thread = new Thread(() -> {
            System.out.println("开始睡眠...");
            // 开始睡眠
            LockSupport.park();
            System.out.println("已被唤醒!");
        });
        thread.start();
        Thread.sleep(1000);
        System.out.println("睡了1秒钟之后开始唤醒...");
        // 开始唤醒
        LockSupport.unpark(thread);
    }
    

    输出:

    开始睡眠...
    睡了1秒钟之后开始唤醒...
    已被唤醒!
    

    从示例中,我们大概就能明白park和unpark方法的作用,park方法类似于wait,unpark方法类似于notify。下面我们再看一下复杂一点的示例,来深刻理解park和unpark方法的作用。

     
     
    二、底层原理
     
    LockSupport类park方法和unpark方法
    public static void park() {
        UNSAFE.park(false, 0L);
    }
    // ...   
    public static void unpark(Thread thread) {
        if (thread != null)
            UNSAFE.unpark(thread);
    }
    
    Unsafe.park和Unsafe.unpark的底层实现原理
    public native void park(boolean isAbsolute, long time);
    public native void unpark(Object var1);
    

      

    每个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来实现的。mutex是操作系统函数,Synchronized底层也是调用mutex互斥锁的。

    在Parker类里的_counter字段,就是用来记录“许可”的。
     
     
    park过程
    当调用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 <wiz_tmp_highlight_tag class="cm-searching">mutex并返回:
    ThreadBlockInVM tbivm(jt);  
    if (_counter > 0)  { // no wait needed  
      _counter = 0;  
      status = pthread_mutex_unlock(_mutex);  
    

      

    否则,再判断等待的时间,然后再调用pthread_cond_wait函数等待,如果等待返回,则把_counter设置为0,unlock <wiz_tmp_highlight_tag class="cm-searching">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过程
    当unpark时,则简单多了,直接设置_counter为1,再unlock <wiz_tmp_highlight_tag class="cm-searching">mutex返回。如果_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") ;  
      }  
    }  
    

      

  • 相关阅读:
    c语言几个字符串处理函数的简单实现
    各种类型排序的实现及比较
    随机洗牌算法Knuth Shuffle和错排公式
    两个栈实现队列
    面试杂题
    面试题——栈的压入、弹出顺序
    Codeforces 455A. Boredom
    PAT A1049. Counting Ones (30)
    Codeforces 895B. XK Segments
    Codeforces 282C. XOR and OR
  • 原文地址:https://www.cnblogs.com/caoxb/p/13139616.html
Copyright © 2011-2022 走看看