学习记录,有不对的或更好见解,还请多多交换
参考
- why-use-a-reentrantlock-if-one-can-use-synchronizedthis
- ReentrantLock (Java Platform SE 8 )
需理解的常识
synchronized
不明确,能够看以下文章,缓缓看,沉下心
- Synchronized Methods (The Java™ Tutorials > Essential Classes > Concurrency)
- Concurrency, Visibility, and Memory (不懂volatile的先看这篇)
看完以上文章,就不必看本文了????
ReenentrantLock概述
ReentrantLock 是对synchronized的扩大。突出的特点就是可重入,更灵便。可重入是指什么?那反过来问不可重入是什么?
不可重入顾名思义就是不能够反复进入,具体指的是在没有开释锁的状况下,不能够再获取锁,否则就会造成死锁dead lock。(很多名词都是英文翻译过去的,所以英文很重要,不然获取的常识就是二手的)
谬误例子如下:
public void test(Object object){
synchronized(object){ // first lock
synchronized(object){ // second lock
//do something
}
}
}
下面的second lock 永远也获取不到锁,所以造成了死锁,程序就卡死在第二次加锁。
次要原理:ReentrantLock类的外部有个Sync类继承了AbstractQueuedSynchronizer(AQS封装了多线程下队列的同步操作)对锁操作进行了封装。NonfairSync和FairSync继承了Sync类,并重载了各自的tryAcquire办法。通过不同的结构器ReentrantLock(),ReentrantLock(boolean fair)来实例化不同的Sync对象,以创立偏心可重入锁 / 不偏心可重入锁对象,后续的所有操作都是基于这个lock对象进行操作。
而对于ReentrantLock来说,它提供了在锁没开释时,能够再次获取锁的办法 tryLock。先来看看ReentrantLock中重要的办法及含意:
lock和synchronized相似,仅当没有其余线程持有该对象的锁时,能力加锁胜利。在其余线程持有锁期间,该线程会进去睡眠状态,(dormant),直到获取到锁。区别在于:若本人对本人再次加锁,是能够取得锁的。(可重入)(注:synchronized对本人加锁两次是死锁)- 结构器中的参数fairness,设为true时,锁会优先让期待最长工夫的线程持有;若为false(默认为false),则不保障线程持有锁的先后顺序。
留神:fairness为true,会重大影响整体性能。而且fairness并不保障线程的调度的偏心(不保障每个线程均匀获取锁,只是让排队最长工夫先的获取而已) tryLock办法不受fairness设置影响。即便有其余线程获取了锁,锁还是能够被持续获取的,最大反对递归 2147483647次(int的最大整数)。(可重入)
注tryLock()在没取得锁时,不会像lock()一样进入睡眠期待;tryLock(long timeout, TimeUnit unit)会睡眠期待timeout时长,同时会fairness规定
unlock开释本人取得的锁,使锁的次数-1。
源码:
1、Sync外部类nonfairTryAcquire办法
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) { //初始态,没有线程持有锁时
if (compareAndSetState(0, acquires)) { //见下文2
setExclusiveOwnerThread(current); //锁住,禁止其余线程拜访
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //对本人线程再次加锁
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc); //减少锁的次数
return true;
}
return false;
}
2、AQS中的compareAndSetState(int expect, int update)办法
protected final boolean compareAndSetState(int expect, int update) {
return STATE.compareAndSet(this, expect, update); //见下文3
}
3、本地办法(C++编写的)compareAndSet位于java.lang.invoke.VarHandle下(常说的CAS)
官网api链接:CAS
如果witness value == exceptedValue,则赋新值newVaule。其中witness value 为main memory中该变量的值(getVolatile获取);赋新值通过setVolatile赋值。
return true,赋值胜利。
return false,变量被其余线程扭转了,赋值失败。
4、NonfairSync类的tryAcquire就是调用Sync中nonfairTryAcquire(acquires);
5、FairSync中的tryAcquire
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
* 翻译:偏心锁,只有在反复获取锁 / 没有其余等得更久的线程在期待获取锁 / 第一个获取锁时,
* 能力获取到锁。
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
6、hasQueuedPredecessors(AQS中)
/*
* Queries whether any threads have been waiting to acquire longer than the current thread.
* 翻译:查看是否有其余想获取锁的线程比以后线程等的长(偏心锁的准则:先服务等得久的)
*/
源码略,因为须要先看懂AQS这个类的实现机制
发表回复