什么是可重入锁呢
顾名思义,就是可以重复进入的锁,学过操作系统或者计组的可参照理解pv,或者多重中断。
demo1(){lock(); //第一次锁demo2(){lock(); // 第二次锁unlock(); }unlock();}
直接从lock()入手翻阅源码
public void lock() {sync.lock();}
它调用的是sync.lock();
在ReentrantLock初始化时,默认是非公平锁,有参构造true则是公平锁
非公平锁:来个线程就先试试能不能插队,不能插队才去后面排队
公平锁:线程都乖乖去后面排队去,不准插队
总而言之,sync就是个内部非公平/公平锁。
再往下看,由于lock()是抽象方法,而sync默认是非公平锁。
调用unfairSync.lock()
final void lock() {// 若CAS抢到锁,记录设置当前线程if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());else// 若没抢到锁acquire(1);
}
点击compareAndSetState
这就是CAS获取锁,unsafe是JDK中用于硬件实现CAS的操作。
不用管它,只需要理解这里就是CAS操作。
若state==0,则更新为1,并且设置好排他线程。即该线程成功抢到锁
那如果没抢到锁呢
public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}
先执行tryAcquire(),可以理解为再次抢锁。
这里nonfairSync重写方法,直接调用nonfairSync.tryAcquire(1)
继续往下调用nonfairTryAcquire(1)
final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();// 如果state=0,再重新尝试一下看能不能抢到锁if (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}// 如果state不为0// 如果这个线程就是之前已经抢到锁的那个,它又要加锁,重入!else if (current == getExclusiveOwnerThread()) {// state递加上去int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
简单理解就是
如果加锁失败,则方法返回到AQS.acquire(1),还需要执行if后面的判断。
简单看下addWaiter();
private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);// Try the fast path of enq; backup to full enq on failure// tail即尾结点Node pred = tail;if (pred != null) {node.prev = pred;if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}enq(node);return node;}
这里维护着一个双向链表,简单来说就是把结点放到链表的尾部,并且更新尾结点。
加锁失败了,把这个线程放在表尾,乖乖排队吧。
这就是加锁的所有过程。
很明显,看来这里是将之前的state一个个减1减回来
public final boolean release(int arg) {if (tryRelease(arg)) {Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;}
tryRelease也就是解锁了
就是将state-1,进行解锁操作。由于可能被可重入了,state-1后不一定为0;如果为0则将记录的线程清空。
解锁很好理解,就不详细赘述了。
lock:
unlock: