zoukankan      html  css  js  c++  java
  • 面试刷题15:synchronized底层是如何实现的?

    image.png


    所有的同步场景都是基于锁。锁在并发编程中发挥重要作用。


    我是李福春,我在准备面试,今天的题目是:




    synchronized底层是如何实现的?

    答: synchronized是在底层的jvm中实现的,即c++写的,synchronized的实现是基于一对monitorenter, monitorexit指令实现的,monitor对象是同步的基本实现单元。


    在java6中,monitor依靠操作系统提供的内部互斥锁,需要在用户态空间和内核态空间切换,所以同步操作是一个比较重的操作,开销比较大。


    在java7之后,monitor有三种不同的实现,即偏斜锁,轻量级锁,重量级锁。


    基于对象头的markword,标记上偏向的线程id, 在没有竞争的条件下,使用的是偏斜锁;
    当有多个线程来竞争偏斜锁,基于cas对对象头的markword来进行竞争,如果拿到了,升级为轻量级锁。
    没拿到则升级为重量级锁;


    锁降级发生在jvm进入安全点检查的时候,对monitor进行降级。


    synchronized底层实现


    对象头结构:

    image.png




    sharedRuntime.cpp 解释器和编译器的运行时基类。 ```cpp

    Handle h_obj(THREAD, obj);
    if (UseBiasedLocking) {
    // Retry fast entry if bias is revoked to avoid unnecessary inflation
    ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK);
    } else {
    ObjectSynchronizer::slow_enter(h_obj, lock, CHECK);
    }

    
    <br />
    <br />偏斜锁逻辑代码:<br />
    
    ```cpp
    
    void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock,
                                      bool attempt_rebias, TRAPS) {
      if (UseBiasedLocking) {
        if (!SafepointSynchronize::is_at_safepoint()) {
          BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);
          if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) {
            return;
          }
      } else {
          assert(!attempt_rebias, "can not rebias toward VM thread");
          BiasedLocking::revoke_at_safepoint(obj);
      }
        assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
      }
     
      slow_enter(obj, lock, THREAD);
    }
    
    


    轻量级锁: ```cpp

    void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
    markOop mark = obj->mark();
    if (mark->is_neutral()) {
    // 将目前的Mark Word复制到Displaced Header上
    lock->set_displaced_header(mark);
    // 利用CAS设置对象的Mark Word
    if (mark == obj()->cas_set_mark((markOop) lock, mark)) {
    TEVENT(slow_enter: release stacklock);
    return;
    }
    // 检查存在竞争
    } else if (mark->has_locker() &&
    THREAD->is_lock_owned((address)mark->locker())) {
    // 清除
    lock->set_displaced_header(NULL);
    return;
    }

    // 重置Displaced Header
    lock->set_displaced_header(markOopDesc::unused_mark());
    ObjectSynchronizer::inflate(THREAD,
    obj(),
    inflate_cause_monitor_enter)->enter(THREAD);
    }

    
    <br />
    <br />
    <br />
    
    
    # java体系中的锁
    
    <br />
    <br />
    <br />java提供的锁有哪些<br />
    <br />
    
    ![image.png](https://img2020.cnblogs.com/other/268922/202003/268922-20200327164950727-2125547505.png)
    
    <br />
    <br />
    <br />
    <br />再入读写锁:<br />
    <br />
    
    ```java
    
    public class RWSample {
      private final Map<String, String> m = new TreeMap<>();
      private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
      private final Lock r = rwl.readLock();
      private final Lock w = rwl.writeLock();
      public String get(String key) {
          r.lock();
          System.out.println("读锁锁定!");
          try {
              return m.get(key);
          } finally {
              r.unlock();
          }
      }
    
      public String put(String key, String entry) {
          w.lock();
      System.out.println("写锁锁定!");
            try {
                return m.put(key, entry);
            } finally {
                w.unlock();
            }
        }
      // …
      }
    
    


    优化的读写锁:StampedLock
    代码如下:
    读取之前先通过validate方法判断是否进入写状态,如果没有进入写状态,不用加读锁,避免了开销;
    否则增加读锁,保证一致性。

    
    public class StampedSample {
      private final StampedLock sl = new StampedLock();
    
      void mutate() {
          long stamp = sl.writeLock();
          try {
              write();
          } finally {
              sl.unlockWrite(stamp);
          }
      }
    
      Data access() {
          long stamp = sl.tryOptimisticRead();
          Data data = read();
          if (!sl.validate(stamp)) {
              stamp = sl.readLock();
              try {
                  data = read();
              } finally {
                  sl.unlockRead(stamp);
              }
          }
          return data;
      }
      // …
    }
    
    

    小结


    本篇先介绍了synchronized的底层实现原理,介绍了java8中引入的3种级别的锁,以及锁升级和降级过程。


    然后介绍了java体系中的其它的锁和优化读写锁使用场景。








    image.png

    原创不易,转载请注明出处。

  • 相关阅读:
    编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议75~78)
    编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议70~74)
    编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议65~69)
    编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议60~64)
    编写高质量代码:改善Java程序的151个建议(第4章:字符串___建议56~59)
    编写高质量代码:改善Java程序的151个建议(第4章:字符串___建议52~55)
    编写高质量代码:改善Java程序的151个建议(第3章:类、对象及方法___建议47~51)
    编写高质量代码:改善Java程序的151个建议(第3章:类、对象及方法___建议41~46)
    IDEA 中 右键新建时,没有新建class的解决方案
    shiro添加注解@RequiresPermissions无效
  • 原文地址:https://www.cnblogs.com/snidget/p/12582454.html
Copyright © 2011-2022 走看看