Java8 ReentrantLock 源码解析

 目录

一、AbstractQueuedSynchronizer

1、定义

2、Unsafe objectFieldOffset和staticFieldOffset

3、Node

二、ReentrantLock

1、acquireQueued

2、lock

3、lockInterruptibly

4、tryLock

5、unlock

 6、其他方法实现总结


       ReentrantLock表示一个可重入的互斥锁,跟synchronized语义基本一致,还扩展了部分功能。当某个线程调用lock方法返回后就表示该线程占有了该锁,如果再次调用lock方法就会立即返回,可通过isHeldByCurrentThread或者getHoldCount方法来判断是否占有该锁。ReentrantLock默认是非公平锁,即哪个线程获取锁是完全随机的,长时间等待的线程不会优先获取锁,如果将构造方法的boolean参数fairness设置为true,则变成了公平锁,该参数默认为false,公平锁可保证长时间等待的线程优先获取锁,但是会导致并发情况下应用程序的吞吐量大幅降低,另外公平锁不能保证系统进程调度的公平,有可能某个线程获取了锁但是没有被系统进程调度分配CPU时间片。ReentrantLock除了实现Lock接口外,还定义了很多public方法来获取锁内部的状态,对于锁使用情况的监控非常有用。ReentrantLock在反序列化的时候都是没有被锁定的状态,无论其在序列化时是否是锁定状态的。ReentrantLock允许同一个线程最多重复lock 2147483647次,超过这个次数限制就会报错。

一、AbstractQueuedSynchronizer

      AbstractQueuedSynchronizer提供了一个实现互斥锁,信号量等同步工具的基础框架,基于FIFO等待队列和一个原子更新的表示状态的int值实现的。AbstractQueuedSynchronizer已经实现了线程阻塞以及操作等待队列的相关方法,子类只需定义如何去修改状态,获取和释放同步器时的状态的方法即可,主要操作状态时必须原子的,可借助getState,setState和compareAndSetState等方法。

     AbstractQueuedSynchronizer本身并不没有实现任何Lock相关的接口,但是提供了acquireQueued / acquireInterruptibly等方法,子类可以据此实现Lock接口。AbstractQueuedSynchronizer本身同时支持互斥模式和共享模式,但是该类本身并不关注其中的差异,而是由子类决定,通常情况下子类只支持一种模式,这时不需要定义方法来支持另一种不支持的模式。

     AbstractQueuedSynchronizer定义了一个内部类ConditionObject,该类是Condition接口的实现类,子类可以利用该类实现互斥模式。AbstractQueuedSynchronizer本身的方法并不会创建一个ConditionObject实例,他的具体语义完全由子类同步器的实现决定。

    AbstractQueuedSynchronizer的序列化实现只存储了一个状态值,没有存储等待的线程队列,因此反序列化的时候等待的线程队列就是空的,子类如果有这方面需要的话,必须要重写readObject方法。

    子类继承AbstractQueuedSynchronizer时,必须实现如下方法:

    实现这些方法必须是线程安全的,代码比较短且是非阻塞的,AbstractQueuedSynchronizer中其他的方法都是final的,不允许被子类改写。

1、定义

     AbstractQueuedSynchronizer继承自AbstractOwnableSynchronizer,该类只有一个属性,private transient Thread exclusiveOwnerThread; 表示占有当前同步器的线程,并且定义了该属性对应的get/set方法,如下:

    AbstractQueuedSynchronizer有两个内部类,ConditionObject和Node,前者是public的,后者是默认的包内访问并且static final的,前者用于实现互斥模式,后者表示等待队列中的一个节点,后面会详细讲解这两个内部类的实现。除此之外定义的属性如下:

  • private transient volatile Node head;  //等待获取锁的链表头,该链表简称同步链表,head和tail都是惰性初始化
  • private transient volatile Node tail;  //等待获取锁的链表尾
  • private volatile int state;  //状态值,主要用于实现锁重入,state等于0表示未被占用,大于0表示累计获取锁的次数
  •  private static final Unsafe unsafe = Unsafe.getUnsafe();
  •  private static final long stateOffset;  //上述state属性在AbstractQueuedSynchronizer实例中的内存偏移量
  •  private static final long headOffset; //同上,head属性的偏移量
  •  private static final long tailOffset;  //同上,tail属性的偏移量
  •  private static final long waitStatusOffset; //Node的waitStatus属性在Node实例中的内存偏移量
  •  private static final long nextOffset;//Node的next属性在Node实例中的内存偏移量

上述static属性都是通过static代码块和Unsafe的方法实现,如下:

还有一个AbstractQueuedLongSynchronizer类,该类的实现和AbstractQueuedSynchronizer完全一致,唯一的改动就是将跟state相关的属性和方法由int类型改成了long类型,即允许锁重入的次数更大了。

2、Unsafe objectFieldOffset和staticFieldOffset

      objectFieldOffset是一个本地方法,用来获取实例字段在实例内存中相对于实例地址的偏移量,可据此算出存储该属性的内存地址,用于原子的修改该属性。与之类似的,有一个staticFieldOffset,用来获取静态字段的内存偏移量,其底层实现如下:

//获取实例字段偏移量
UNSAFE_ENTRY(jlong, Unsafe_ObjectFieldOffset(JNIEnv *env, jobject unsafe, jobject field))
  UnsafeWrapper("Unsafe_ObjectFieldOffset");
  
  return find_field_offset(field, 0, THREAD);
UNSAFE_END

//还有一个获取静态字段偏移量的方法
UNSAFE_ENTRY(jlong, Unsafe_StaticFieldOffset(JNIEnv *env, jobject unsafe, jobject field))
  UnsafeWrapper("Unsafe_StaticFieldOffset");
  return find_field_offset(field, 1, THREAD);
UNSAFE_END

jint find_field_offset(jobject field, int must_be_static, TRAPS) {
  if (field == NULL) {
    //field为空,抛出异常
    THROW_0(vmSymbols::java_lang_NullPointerException());
  }
  
  //解析出java_lang_reflect_Field实例oop
  oop reflected   = JNIHandles::resolve_non_null(field);
  //获取klass
  oop mirror      = java_lang_reflect_Field::clazz(reflected);
  Klass* k      = java_lang_Class::as_Klass(mirror);
  //获取slot属性,slot表示该字段是第几个字段
  int slot        = java_lang_reflect_Field::slot(reflected);
  //获取字段修饰符
  int modifiers   = java_lang_reflect_Field::modifiers(reflected);

  if (must_be_static >= 0) {
    //是否静态字段,如果是really_is_static就等于1
    int really_is_static = ((modifiers & JVM_ACC_STATIC) != 0);
    if (must_be_static != really_is_static) {
      THROW_0(vmSymbols::java_lang_IllegalArgumentException());
    }
  }
  //获取字段偏移量
  int offset = InstanceKlass::cast(k)->field_offset(slot);
  return field_offset_from_byte_offset(offset);
}

//获取slot属性
int java_lang_reflect_Field::slot(oop reflect) {
  assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
  return reflect->int_field(slot_offset);
}

inline jlong field_offset_from_byte_offset(jlong byte_offset) {
  return byte_offset;
}

3、Node

      Node表示等待队列中的一个节点,其包含的属性如下:

  • volatile int waitStatus; //当前Node节点的状态
  • volatile Node prev;  //前一个Node节点
  • volatile Node next;  //下一个Node节点
  • volatile Thread thread; //关联的线程
  • Node nextWaiter;  //用来构造一个在Condition上等待即调用await方法的Node节点链表,如果nextWaiter是一个常量值SHARED,则表示当前Node是共享模式

       Node定义了以下的常量值:

  • static final Node SHARED = new Node();  //表示共享模式,给nextWaiter复制
  • static final Node EXCLUSIVE = null
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值