
第一点:因为 synchronized 的原子性是通过操作系统的Mutex Lock互斥量实现的,所以每次申请互斥量都需要从用户态转换到内核态。
第二点:JVM 线程是和内核线程 1:1 实现的,所以对线程的阻塞和唤醒也是需要从用户态转换到内核态。
public abstract class AbstractQueuedSynchronizer {// 头节点,懒加载private transient volatile Node head;// 尾节点,懒加载private transient volatile Node tail;// 锁状态和锁重入的数量,0 代表无线程占用private volatile int state;}
static final class Node {// 节点状态volatile int waitStatus;// 前继节点volatile Node prev;// 后继节点volatile Node next;// 阻塞的线程volatile Thread thread;// 下个等待节点,单链表,作用类似于Object.wait()的等待队列Node nextWaiter;// Used by addWaiterNode(Thread thread, Node mode) {this.nextWaiter = mode;this.thread = thread;}// Used by ConditionNode(Thread thread, int waitStatus) {this.waitStatus = waitStatus;this.thread = thread;}}
CANCELLED(1):取消状态,标志该线程不再参与锁的争抢 SIGNAL(-1):标记后继节点的线程需要被阻塞 CONDITION(-2):同步阻塞状态,类似调用了Object.wait() PROPAGATE(-3):共享模式,同步状态可传播状态 0:初始状态
// 默认初始化非公平锁public ReentrantLock() {sync = new NonfairSync();}// 可以通过参数指定公平锁public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}
// lock()方法源码final void lock() {// 先通过CAS的操作将state值改为1,期待值为0;if (compareAndSetState(0, 1))// 如果CAS成功,将独占线程设置为当前线程setExclusiveOwnerThread(Thread.currentThread());else// 失败代表有竞争acquire(1);}
// acquire()源码public final void acquire(int arg) {// 再次尝试获取锁,如果失败将当前线程加入等待队列进行阻塞// acquireQueued()也会有尝试获取锁的逻辑if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}
// 非公平锁的实现protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}// 非公平锁尝试获取锁final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();// 获取 stateint c = getState();// 如果 state 为 0 代表没有线程占用,可以获取锁if (c == 0) {// 通过CAS的操作修改state的值(保证原子性)if (compareAndSetState(0, acquires)) {// 如果成功将独占线程变量设置为当前线程并返回setExclusiveOwnerThread(current);return true;}}// 如果独占线程是当前线程,证明当前线程已经获取到锁,所以进行重入else if (current == getExclusiveOwnerThread()) {// 重入次数int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");// 不需要CAS操作,因为进入到这里的线程已经获取到了锁自然没有竞争,直接设置值即可setState(nextc);return true;}// 抢占失败或者非重入的返回失败return false;}
如果 state 值为 0 代表没有线程占用,可以进行一次 CAS 操作去修改 state 的值,返回 CAS 结果;
如果 state 不为 0 进行重入锁的判断,判断独占线程是否是当前线程,如果是进行锁的重入,这里不需要对 state 进行 CAS 操作,因为进入到这里的线程已经获取到了锁自然没有竞争,直接设置 state 值即可。
// addWaiter源码private Node addWaiter(Node mode) {// 将当前线程存储到 Node 节点内Node node = new Node(Thread.currentThread(), mode);// Try the fast path of enq; backup to full enq on failureNode pred = tail;// 如果尾节点不为空if (pred != null) {// 将当前线程节点的pre指向尾节点:tail <- nodenode.prev = pred;// CAS 操作将尾节点改为当前线程节点nodeif (compareAndSetTail(pred, node)) {// 如果修改成功// 将之前 pre(之前的尾节点)的 next 指向 node(现在的尾节点)pred.next = node;// 完成等待队列的添加,直接返回return node;}}// 尾节点为空或 CAS 失败,会走到这里enq(node);return node;}// 自旋直到将node加入到等待队列里private Node enq(final Node node) {for (;;) {Node t = tail;// 走到这里并且尾节点为空代表第一次进行竞争抢占锁if (t == null) { // Must initialize// CAS 设置等待队列的head节点if (compareAndSetHead(new Node()))// CAS 操作成功设置尾节tail = head;// 进入下一轮循环} else {// 尾节点不为空就能将node的prev指向尾节点node.prev = t;// CAS 修改尾节点为 node(这块是循环的出口,只有加入等待队列成功才会跳出循环)if (compareAndSetTail(t, node)) {// CAS 成功就next连上node并返回t.next = node;return t;}// CAS 失败代表有竞争,进入下一轮循环}}}
// acquireQueued() 源码final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;// 自旋for (;;) {// 获取node节点的前继节点final Node p = node.predecessor();// 如果前继节点是头节点,就尝试获取锁(优化)if (p == head && tryAcquire(arg)) {// 获取成功将当前节点设置为头节点setHead(node);// 断开之前的头节点p.next = null; // help GCfailed = false;// 返回代表获取锁成功,返回执行业务代码return interrupted;}// 如果前继节点不是头节点或获取锁失败会走到这里// 检查当前节点是否应该阻塞if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}
如果是,尝试获取锁,失败就尝试阻塞线程;
如果不是,直接尝试阻塞线程。
// 判断当前d节点是否应该阻塞private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {int ws = pred.waitStatus;// 如果前继节点的waitStatus为SIGNA就返回true进行阻塞操作if (ws == Node.SIGNAL)return true;if (ws > 0) {// 大于 0 代表取消争抢锁,从后往前遍历,直到 waitStatus 不大于零do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);pred.next = node;} else {// 初始化状态将前继节点的 waitStatus 值改为 SIGNAL 状态compareAndSetWaitStatus(pred, ws, Node.SIGNAL);}// 返回false后会再次进入下一轮循环return false;}
private final boolean parkAndCheckInterrupt() {// 线程阻塞方法,调用本地方法阻塞当前线程LockSupport.park(this);return Thread.interrupted();}
public final boolean tryAcquireNanos(int arg, long nanosTimeout)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();// 先通过tryAcquire尝试获取一次锁,如果失败调用 doAcquireNanos(arg, nanosTimeout)return tryAcquire(arg) ||doAcquireNanos(arg, nanosTimeout);}// 自旋超时时间阈值static final long spinForTimeoutThreshold = 1000L;private boolean doAcquireNanos(int arg, long nanosTimeout)throws InterruptedException {// 检查设置的超时时间if (nanosTimeout <= 0L)return false;// 计算方法的返回的时间戳 deadlinefinal long deadline = System.nanoTime() + nanosTimeout;// 先将当前线程加到等待队列尾部final Node node = addWaiter(Node.EXCLUSIVE);boolean failed = true;try {for (;;) {// 获取当前线程节点的前继节点final Node p = node.predecessor();// 如果前面继节点是 head 就去尝试获取锁if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return true;}// 获取剩余超时时间 nanosTimeoutnanosTimeout = deadline - System.nanoTime();// nanosTimeout 小于 0 代表超时时间到,返回 falseif (nanosTimeout <= 0L)return false;// 检查是否应该阻塞线程// 如果应该阻塞,判断 nanosTimeout 是否大于 spinForTimeoutThreshold(1000纳妙)if (shouldParkAfterFailedAcquire(p, node) &&nanosTimeout > spinForTimeoutThreshold)// 将线程阻塞 nanosTimeout 的时间,等时间到后线程自动唤醒,进行下一次循环判断时间后返回falseLockSupport.parkNanos(this, nanosTimeout);if (Thread.interrupted())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}}
public void unlock() {sync.release(1);}public final boolean release(int arg) {// 先尝试解锁,如果成功再唤醒head的后继节点if (tryRelease(arg)) {Node h = head;// head 不等于 null 并且不等于 0 就唤醒后继节点if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;}
protected final boolean tryRelease(int releases) {// 计算解锁后的state值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;}
private void unparkSuccessor(Node node) {int ws = node.waitStatus;if (ws < 0)compareAndSetWaitStatus(node, ws, 0);Node s = node.next;// 如果后继节点为空或者状态为已取消if (s == null || s.waitStatus > 0) {s = null;// 从尾节点tail从后往前遍历,找到最靠前的不为null且状态不为取消的for (Node t = tail; t != null && t != node; t = t.prev)if (t.waitStatus <= 0)s = t;}if (s != null)// 阻塞线程LockSupport.unpark(s.thread);}
lockInterruptibly() 可中断加锁
public void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}public final void acquireInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();// 先尝试获取锁if (!tryAcquire(arg))// 获取锁失败进入 doAcquireInterruptiblydoAcquireInterruptibly(arg);}
private void doAcquireInterruptibly(int arg)throws InterruptedException {final Node node = addWaiter(Node.EXCLUSIVE);boolean failed = true;try {for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())// 重点就在这里,当调用线程的interrupt()中断方法时,阻塞的线程会被唤醒,并抛出异常throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}}

三. ReentrantLock 如何保证线程安全?
Lock lock = new ReentrantLock();int i = 0;// 伪代码...try {lock.lock();i ++;} finally {lock.unlock();}
!
文章转载自阿东编程之路,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




