一、公平、非公平锁的区别
通过ReentrantLock的源码来讲解公平锁和非公平锁。
公平锁与非公平锁的lock()方法唯一的区别就在于公平锁在获取同步状态时多了一个限制条件:hasQueuedPredecessors(),它是公平锁加锁时判断等待队列中是否存在有效节点的方法。
公平锁:公平锁讲究先来先到,线程在获取锁时,如果这个锁的等待队列中已经有线程在等待,那么当前线程就会进入等待队列中。
非公平锁:不管是否有等待队列,如果可以获取锁,则立刻占有锁对象。也就是说队列的第一个排队线程在unpark(),之后还是需要竞争锁(存在线程竞争的情况下)。
二、lock()源码
三、acquire()源码
此方法是独占模式下线程获取共享资源的顶层入口。
3.1 tryAcquire(int arg)
此方法尝试去获取独占资源。如果获取成功,则直接返回true,否则直接返回false。
3.2 addWaiter(Node mode)
此方法用于将当前线程加入到等待队列的队尾,并返回当前线程所在的结点。
private Node addWaiter(Node mode) { //以给定模式构造结点。mode有两种:EXCLUSIVE(独占)和SHARED(共享) Node node = new Node(Thread.currentThread(), mode); //尝试快速方式直接放到队尾。 Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } //当队列没有元素时,则通过enq创建队列 enq(node); return node; }
注:通过enq创建队列时,底层会默认创建一个new Node()作为伪节点,占在队列首位,第二位才是被传入的node节点。
3.3 acquireQueue(final Node node, int arg)
内部会调用tryAcquire()方法,如果获取失败,会通过parkAndCheckInterrupt()方法将队列中的Node置为等待状态,直到占用线程调用unLock()方法或中断该线程。