目录
2、Unsafe objectFieldOffset和staticFieldOffset
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