Lock在硬件层面依赖CPU指令,完全由Java代码完成,底层利用LockSupport类和Unsafe类进行操作;
虽然锁有很多实现,但是都依赖AbstractQueuedSynchronizer类,我们用ReentrantLock进行讲解;
ReentrantLock调用过程ReentrantLock类的API调用都委托给一个内部类 Sync ,而该类继承了 AbstractQueuedSynchronizer类;
public class ReentrantLock implements Lock, java.io.Serializable { ...... abstract static class Sync extends AbstractQueuedSynchronizer { ......
而Sync又分为两个子类:公平锁和非公平锁,默认为非公平锁
/** * Sync object for non-fair locks */ static final class NonfairSync extends Sync {
/** * Sync object for fair locks */ static final class FairSync extends Sync {
Lock的调用过程如下图(其中涉及到 ReentrantLock类、Sync(抽象类)、AbstractQueuedSynchronizer类,NofairSync类,这些类将 Template方法用的淋漓尽致,相当赞):
先来一张类依赖图:
再来一张lock调用图:
Lock API详解自底而上来看,由被调用一步步向上分析
nofairTryAcquire/** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { 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; }
来看这段代码,首先获取当前状态(初始化为0),当它等于0的时候,代表还没有任何线程获得该锁,然后通过CAS(底层是通过CompareAndSwapInt实现)改变state,并且设置当前线程为持有锁的线程;其他线程会直接返回false;当该线程重入的时候,state已经不等于0,这个时候并不需要CAS,因为该线程已经持有锁,然后会重新通过setState设置state的值,这里就实现了一个偏向锁的功能,即锁偏向该线程;
addWaiter只有当锁被一个线程持有,另外一个线程请求获得该锁的时候才会进入这个方法
/** * Creates and enqueues node for current thread and given mode. * * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared * @return the new node */ private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } enq(node); return node; }
首先持有该锁之外的线程进入到该方法,这里涉及到一个CLH(三个人的名字首字母:Craig, Landin, and Hagersten)队列,其实就是一个链表,
简单说下CLH队列:
CLH队列由node节点组成,mode代表每个Node有两种模式:共享模式和排他模式,并且维护了一个状态:waitStatus,可取值如下:
CANCELLED = 1 由于超时或者被打断,该线程被取消,将不会被block;
SIGNAL = -1 当前线程的后继节点线程通过park正处于或即将处于block状态;
CONDITION = -2 当前线程正处于条件队列,正式因为调用了condition.await造成阻塞;
PROPAGATE = -3 共享锁应该被传播出去
首先,new一个节点,这个时候模式为:mode为 Node.EXCLUSIVE,默认为null即排它锁;
然后: