JAVA编程-多线程协调工具_ReentrantLock

1.来历

大多数情况下,不仅不存在多线程竞争,还存在锁由同一线程多次获得的情况,synchronized关键字的偏向锁与ReentrantLock就是在这种情况下出现的

在1.6前, synchronized关键字是用是用系统调用实现的(例如:pthread_mutex_t). 获取锁动作与释放锁动作.

在1.5出现了JUC库, 例如ReentrantLock.

JDK版本 锁实现 获取锁动作 释放锁动作
1.5 synchronized关键字 系统调用 例如:pthread_mutex_t 同上
1.5 ReentrantLock 在不存在资源竞争的情况下不会系统调用,反之 同上
1.6 synchronized关键字 在不存在资源竞争的情况下不会系统调用,反之.依据对象头中的线程ID是否是当前持有线程, 同上
1.6 ReentrantLock 在不存在资源竞争的情况下不会系统调用,反之 同上

2.关键词

volatile + cas操作, 等待队列, 线程持有者, 公平锁与非公平锁, 减少系统调用, AQS

3.ReentrantLock的实现

内部变量

state + 等待线程的队列 + 当前线程持有者

执行逻辑

  • 获取成功时; 获取state字段时,值为0或当前线程持有者是自己,则判定成功. 且state字段+1(cas操作).

    公平锁在获取成功后,会再检查是否需要排队

    非公平锁在获取成功后直接使用返回,不检查是否需要排队.

  • 获取失败时; 将当前线程追加到等待队列中,并且park当前线程(系统调用).

  • 释放锁时; 状态变量-1, 如果没有人排队,则返回. 如果队列中有线程,则叫醒最早排队的那个线程(系统调用).

4.synchronized关键字的实现 (源码没看懂, 希望能有大神带入门)

synchronized由字节码指令(monitorentermonitorexit)实现.

下面代码摘自 https://download.java.net/openjdk/jdk6/

monitorenter指令的实现

目录地址 /hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:585

 IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem))
 if (PrintBiasedLockingStatistics) {
   Atomic::inc(BiasedLocking::slow_path_entry_count_addr());
 }
 Handle h_obj(thread, elem->obj());
  
 if (UseBiasedLocking) {
   // Retry fast entry if bias is revoked to avoid unnecessary inflation
   ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK);
 } else {
   ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
 }

目录地址 /hotspot/src/share/vm/runtime/synchronizer.cpp:158

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);
}

void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
  markOop mark = obj->mark();
  assert(!mark->has_bias_pattern(), "should not see bias pattern here");
  if (mark->is_neutral()) {
    // Anticipate successful CAS -- the ST of the displaced mark must
    // be visible <= the ST performed by the CAS.
    lock->set_displaced_header(mark);
    if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {
      TEVENT (slow_enter: release stacklock) ;
      return ;
    }
    // Fall through to inflate() ...
  } else
  if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
    assert(lock != mark->locker(), "must not re-lock the same lock");
    assert(lock != (BasicLock*)obj->mark(), "don't relock with same BasicLock");
    lock->set_displaced_header(NULL);
    return;
  }

  // The object header will never be displaced to this lock,
  // so it does not matter what the value is, except that it
  // must be non-zero to avoid looking like a re-entrant lock,
  // and must not look locked either.
  lock->set_displaced_header(markOopDesc::unused_mark());
  ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
}

monitorexit指令的实现

目录地址 /hotspot/src/share/vm/interpreter/interpreterRuntime.cpp:610

 IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorexit(JavaThread* thread, BasicObjectLock* elem))
 Handle h_obj(thread, elem->obj());
 if (elem == NULL || h_obj()->is_unlocked()) {
   THROW(vmSymbols::java_lang_IllegalMonitorStateException());
 }
 ObjectSynchronizer::slow_exit(h_obj(), elem->lock(), thread);
 // Free entry. This must be done here, since a pending exception might be installed on
 // exit. If it is not cleared, the exception handling code will try to unlock the monitor again.
 elem->set_obj(NULL);

目录地址 /hotspot/src/share/vm/runtime/synchronizer.cpp:240

// This routine is used to handle interpreter/compiler slow case
// We don't need to use fast path here, because it must have
// failed in the interpreter/compiler code. Simply use the heavy
// weight monitor should be ok, unless someone find otherwise.
void ObjectSynchronizer::slow_exit(oop object, BasicLock* lock, TRAPS) {
  fast_exit (object, lock, THREAD) ;
}

void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) {
  assert(!object->mark()->has_bias_pattern(), "should not see bias pattern here");
  // if displaced header is null, the previous enter is recursive enter, no-op
  markOop dhw = lock->displaced_header();
  markOop mark ;
  if (dhw == NULL) {
     // Recursive stack-lock.
     // Diagnostics -- Could be: stack-locked, inflating, inflated.
     mark = object->mark() ;
     assert (!mark->is_neutral(), "invariant") ;
     if (mark->has_locker() && mark != markOopDesc::INFLATING()) {
        assert(THREAD->is_lock_owned((address)mark->locker()), "invariant") ;
     }
     if (mark->has_monitor()) {
        ObjectMonitor * m = mark->monitor() ;
        assert(((oop)(m->object()))->mark() == mark, "invariant") ;
        assert(m->is_entered(THREAD), "invariant") ;
     }
     return ;
  }
  mark = object->mark() ;
  // If the object is stack-locked by the current thread, try to
  // swing the displaced header from the box back to the mark.
  if (mark == (markOop) lock) {
     assert (dhw->is_neutral(), "invariant") ;
     if ((markOop) Atomic::cmpxchg_ptr (dhw, object->mark_addr(), mark) == mark) {
        TEVENT (fast_exit: release stacklock) ;
        return;
     }
  }
  ObjectSynchronizer::inflate(THREAD, object)->exit (THREAD) ;
}

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

备案信息公示
京ICP备18003381号
京ICP备18003381号-1