NonfairSync锁是重入锁的一种非公平锁,是指尝试获取锁的线程,如果失败则进入AQS锁等待队列中。在ReentaintLock类会默认创建一个非公平锁。
* Creates an instance of {@code ReentrantLock}. * This is equivalent to using {@code ReentrantLock(false)}. */ public ReentrantLock() { sync = new NonfairSync(); }
/** * Sync object for non-fair locks */ static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }
1.首先尝试将当前AQS 的state状态由0到1,如果修改成功则表明当前AQS的锁是0,没有别其他占用锁,并设置“ setExclusiveOwnerThread(Thread.currentThread());” 当前线程设置为持有锁的线程。如果设置失败则会调用AQS的 “ acquire(1);”方法。
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
2. accquire(1)方法会调用尝试获得锁失败并且已经加入AQS请求队列中,则会执行线程中断,表明自己已经被加入等待队列中。AQS的tryAcquire(arg)方法会调用NonfairSync中的tryAcquire(int acquires)方法。
/** * 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; }
3.首先获取当前线程和当前AQS中的状态(state)。如果AQS状态为0,则尝试一次CAS操作并把当前AQS的state设置为acquires,如果设置成功,则表明当前线程设置为持有锁的线程并返回true。
4.如果持有锁的线程是当前线程则将AQS状态值(state)增加acquires,设置成功则返回成功,否则返回失败表明获取锁失败。
5.addWaiter(Node mode)方法是将新建一个新的node添加到队列中,并返回此新建的节点。
/** * 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; }
6.首先获取当前的队列尾部的节点,如果尾节点不为空,这将新建的节点node添加到尾部节点并执行一次CAS操作将新建的节点设置为tail节点,如果成功则将返回此进行的节点。如果失败,则,执行 enq(node);方法。
private Node enq(final Node node) { for (;;) { Node t = tail; if (t == null) { // Must initialize if (compareAndSetHead(new Node())) 8. } else { node.prev = t; if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }
7.死循环执行 首先获取tail节点,如果tail节点为空则进行一次CAS设置header节点初始化操作。然后设置tail节点为head节点。否则将新传递的节点设置为tail节点并返回。
8.acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
9.进入方法是一个死循环 获取当前节点的前一个处理的节点,有且当前节点的前一个处理的节点是head节点并且尝试获取锁成功才返回的。设置head节点为当前节点并返回是中断状态。至此锁过程完毕。
二、释放锁
1.调用unlock方法进行释放锁实际上调用户AQS的release(arg)方法 如下:
if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
2.首先会尝试释放锁,unparkSuccessor(h)方法释放成功后会将唤醒其他等待的线程node进行继续操作。
3.执行tryRelease(arg)方法如下
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
4.首先获取AQS当前状态和要释放数量之差,判断如果当前线程不是当前锁所拥有的线程则会直接抛出异常。
5.如果之差为0说明完全释放成功。设置当前拥有的线程为空初始化AQS状态为0并返回true状态,否则设置AQS状态并返回false状态。
相关推荐
这份资源旨在详细讲解 Java 中的 Locks 框架,特别关注 ReentrantLock 的使用和原理。Locks 框架提供了比传统的 synchronized 关键字更强大、更灵活的线程同步机制,而 ReentrantLock 是其中的一种重要实现。 Locks ...
带你看看Javad的锁-ReentrantLock前言ReentrantLock简介Synchronized对比用法源码分析代码结构方法分析SyncNonfairSyncFairSync非公平锁VS公平锁什么是公平非公平ReentrantLockReentrantLock的构造函数lock加锁方法...
这份资源旨在介绍 Java Locks 框架中的 Lock 接口及其相关内容。Lock 接口是 Locks 框架的核心,提供了更加灵活和可控的线程同步机制,用于替代传统的 synchronized 关键字。 Lock 接口概述: 简要介绍 Lock 接口,...
Lock锁,一种线程同步机制,其主要功能是防止多个线程同时访问同一代码块,从而避免因并发问题引发的数据不一致或其他错误。...总的来说,Lock锁是Java多线程编程中的重要工具,能够有效保障程序运行的正确性和稳定性。
Rivers Lock Rivers Lock,是一款轻量级的分布式锁软件,不依赖Zookeeper,... ReentrantLock lock = new ReentrantLock(); if(lock.lock("锁名称")) { System.out.println("success"); lock.unLock("锁名称"); }
Реализованочерезjava.util.concurrent.locks.ReentrantLock например: public void add(final Person person) { final ReentrantLock lock = this.lock; lock.lock(); try { ...
目录synchronized的缺陷Lock和ReentrantLock常用方法ReadWriteLock和ReentrantReadWriteLockLock和synchronized区别synchronized锁升级公平锁和非公平锁 synchronized的缺陷 众所周知,synchronized锁是JAVA的关键字...
Lock lock = new ReentrantLock(); 请求锁,如果锁被当前另一个线程持有,则阻塞。 void lock(); 释放锁 void unlock(); 非阻塞型lock() boolean tryLock(); (2) 使用基本结构 locker.lock(); try{ ...
b:在实际使用中,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一...
Map 在使用过程中不断的往里面存放数据,当数量达到了 16 * 0.75 = 12 就需要将当前 16 的容量进行扩容,而扩容这个过程涉及到 rehash、复制数据等操作,所以非常消耗性能。 因此通常建议能提前预估 HashMap 的大小...