学习记录,有不对的或更好看法,还请多多交流html
synchronized
不明白,能够看如下文章,慢慢看,沉下心java
看完以上文章,就不用看本文了😀api
ReentrantLock
是对synchronized
的扩展。突出的特色就是可重入,更灵活。可重入是指什么?那反过来问不可重入是什么?
不可重入顾名思义就是不能够重复进入,具体指的是在没有释放锁的状况下,不能够再获取锁,不然就会形成死锁dead lock。(不少名词都是英文翻译过来的,因此英文很重要,否则获取的知识就是二手的)
错误例子以下:多线程
public void test(Object object){ synchronized(object){ // first lock synchronized(object){ // second lock //do something } } }
上面的second lock 永远也获取不到锁,因此形成了死锁,程序就卡死在第二次加锁。oracle
主要原理:ReentrantLock类的内部有个Sync类继承了AbstractQueuedSynchronizer(AQS封装了多线程下队列的同步操做)对锁操做进行了封装。NonfairSync和FairSync继承了Sync类,并重载了各自的tryAcquire方法。经过不一样的构造器ReentrantLock(),ReentrantLock(boolean fair)来实例化不一样的Sync对象,以建立公平可重入锁 / 不公平可重入锁对象,后续的全部操做都是基于这个lock对象进行操做。less
而对于ReentrantLock来讲,它提供了在锁没释放时,能够再次获取锁的方法 tryLock
。先来看看ReentrantLock中重要的方法及含义:性能
lock
和synchronized相似,仅当没有其余线程持有该对象的锁时,才能加锁成功。在其余线程持有锁期间,该线程会进去睡眠状态,(dormant),直到获取到锁。区别在于:若本身对本身再次加锁,是能够得到锁的。(可重入)(注:synchronized对本身加锁两次是死锁)注意:fairness为true,会严重影响总体性能。并且fairness并不保证线程的调度的公平(不保证每一个线程平均获取锁,只是让排队最长时间先的获取而已)
tryLock
方法不受fairness设置影响。即便有其余线程获取了锁,锁仍是能够被继续获取的,最大支持递归 2147483647次(int的最大整数)。(可重入)注tryLock()在没得到锁时,不会像lock()同样进入睡眠等待;tryLock(long timeout, TimeUnit unit)会睡眠等待timeout时长,同时会fairness规则
学习
unlock
释放本身得到的锁,使锁的次数-1。源码:
一、Sync
内部类nonfairTryAcquire
方法ui
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; }
二、AQS中的compareAndSetState(int expect, int update)
方法this
protected final boolean compareAndSetState(int expect, int update) { return STATE.compareAndSet(this, expect, update); //见下文3 }
三、本地方法(C++编写的)compareAndSet位于java.lang.invoke.VarHandle下(常说的CAS)
官网api连接:CAS
若是witness value == exceptedValue,则赋新值newVaule。其中witness value 为main memory中该变量的值(getVolatile获取);赋新值经过setVolatile赋值。 return true,赋值成功。 return false,变量被其余线程改变了,赋值失败。
四、NonfairSync类的tryAcquire就是调用Sync中nonfairTryAcquire(acquires);
五、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; }
六、hasQueuedPredecessors(AQS中)
/* * Queries whether any threads have been waiting to acquire longer than the current thread. * 翻译:查看是否有其余想获取锁的线程比当前线程等的长(公平锁的原则:先服务等得久的) */ 源码略,由于须要先看懂AQS这个类的实现机制