lock
lock 中的方法:

AQS: AbstractQueuedSynchronizer 抽象队列同步器 ( juc中最复杂的一个类?? 它做了什么事情?)
主要就是支持两个操作: 获取锁 和 释放锁 。
获取锁: 首先判断状态是否允许获取锁, 如果允许获取锁,则获取锁,并修改状态; 如果获取锁失败,则进入到阻塞队列。
释放锁: 修改状态,阻塞队列中的阻塞线程尝试获取锁。
要实现 获取和释放锁,需要有这几个东西:
状态位 (用来判断能不能获取锁)
阻塞队列 (阻塞线程放到这里面)
阻塞和唤醒线程
具体的实现:(在AQS中)
有一个 int 类型的 state 变量, 并且用volatile进行了修饰。
如何阻塞(挂起)和唤醒线程? 可以用wait和notify但是不合适?为什么? 采用的 LockSupport 类中的 park 和 unpark等方法来实现的阻塞和唤醒线程。
采用 CHL来实现阻塞队列。 完成入队和出队的过程。队列中的元素都是 Node 类型。
ReentrantLock:
lock()方法的实现
1) 调用syn的lock()方法
公平锁:
final void lock() { acquire(1); }
2) AQS 中的 acquire 方法 (先尝试获取锁,如果获取失败,则入队到阻塞队列中)
public final void acquire(int arg) { if (!tryAcquire(arg) && // 尝试获取锁 如果获取到 则结束了 if中的条件不满足 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 如果当前线程的中断状态为true, 则执行 selfInterrupt方法,否则不执行 selfInterrupt(); // 将 自己线程的中断状态设置为 true; 有什么用呢? 不清楚!! }
3) ReentrantLock中的 FairSync 中重写了 tryAcquire 方法 (尝试获取锁)
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); // 当前线程 int c = getState(); // 获取同步状态 if (c == 0) { // 表示没有线程持有锁 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); // 设置当前线程为 独占锁(排他锁) 的持有者 return true; } } else if (current == getExclusiveOwnerThread()) { // 如果当前线程是 持有锁的线程 int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); // 修改同步状态 可重入锁,进入一次,同步状态+1 return true; } return false; } }
AQS中的 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 Node pred = tail; if (pred != null) { /// 如果已经存在了阻塞队列,则直接入队,添加到队尾 node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } enq(node); // 不存在阻塞队列,则 return node; }
AQS中的 enq 方法。
private Node enq(final Node node) { for (;;) { Node t = tail; if (t == null) { // Must initialize // 如果尾节点为null if (compareAndSetHead(new Node())) // 设置头节点 可见 头节点是一个尾节点,头节点的下一个结点才是正式的头节点 tail = head; } else { node.prev = t; // 当前结点作为尾结点 入队! if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }
AQS 中的 acquireQueued 方法。 返回的是当前线程的中断状态,如果执行了该线程了 interrupt方法,那么中断状态就是true,就会返回true,否则,返回false.
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { // 死循环 final Node p = node.predecessor(); // 获取 node的前一个结点 if (p == head && tryAcquire(arg)) { / /如果当前结点的前一个结点是 头节点,并且 tryAcquire 方法尝试获取锁,成功获取到 setHead(node); // 设置当前结点为头节点 p.next = null; // help GC failed = false; return interrupted; // 返回false,则 acquire中的 if中的判断语句为假,不执行 selfInterrupt()方法, } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
AQS的中的Node类中的predecessor方法, 来获取的node的前一个结点。
final Node predecessor() throws NullPointerException { Node p = prev; if (p == null) throw new NullPointerException(); else return p; }
AQS 的 shouldParkAfterFailedAcquire 方法
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { int ws = pred.waitStatus; // 上一个结点的等待状态 if (ws == Node.SIGNAL) /* * This node has already set status asking a release * to signal it, so it can safely park. */ return true; if (ws > 0) { /* * Predecessor was cancelled. Skip over predecessors and * indicate retry. */ do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { /* * waitStatus must be 0 or PROPAGATE. Indicate that we * need a signal, but don't park yet. Caller will need to * retry to make sure it cannot acquire before parking. */ compareAndSetWaitStatus(pred, ws, Node.SIGNAL); // 设置上一个结点的 waitState状态为 SIGNAL, 这样才能唤醒下一个结点 } return false; }
AQS 中的 parkAndCheckInterrupt 方法
private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); // 返回当前线程的中断状态 }
LockSupport中的park 方法。
public static void park(Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(false, 0L); //挂起的当前线程?? setBlocker(t, null); }
unlock方法的实现:
public void unlock() { sync.release(1); }
1)调用AQS中的 release 方法
public final boolean release(int arg) { if (tryRelease(arg)) { // 如果当前没有线程占有该锁 Node h = head; if (h != null && h.waitStatus != 0) // 保证阻塞队列中还有被挂起的线程 unparkSuccessor(h); // h是头结点 return true; } return false; }
2)Sync中重写了 tryRelease 方法
protected final boolean tryRelease(int releases) { // 如果没有线程占有锁,则返回true, 否则,返回 false. int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) // 如果当前线程不是该独占锁的拥有者,则抛出异常 throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { // 如果同步状态的值为0 ,则没有线程占有此独占锁 free = true; setExclusiveOwnerThread(null); } setState(c); // 更新同步状态的值 return free; }
3) AQS 中的 unparkSuccessor 方法
private void unparkSuccessor(Node node) { /* * If status is negative (i.e., possibly needing signal) try * to clear in anticipation of signalling. It is OK if this * fails or if status is changed by waiting thread. */ int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); /* * Thread to unpark is held in successor, which is normally * just the next node. But if cancelled or apparently null, * traverse backwards from tail to find the actual * non-cancelled successor. */ Node s = node.next; if (s == null || s.waitStatus > 0) { s = 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); // 唤醒线程 还是通过 LockSupport 类中的方法,不过umpark方法需要传入要被唤醒的线程
}
非公平锁的 lock实现:
final void lock() { if (compareAndSetState(0, 1)) // 多了这个直接获取锁过程 setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
tryLock 方法的实现:
public boolean tryLock() { return sync.nonfairTryAcquire(1); // 获取到返回true, 没获取到返回false }
1)Sync中的 nonfairTryAcquire 方法
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; }
带时间的 tryLock 方法的实现:
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); }
1)调用AQS中的 tryAcquireNanos 方法
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) // 如果当前线程的中断状态为true, 则抛出异常。 throw new InterruptedException(); return tryAcquire(arg) || // 先尝试获取一次锁,如果成功,直接返回true doAcquireNanos(arg, nanosTimeout); // }
2)调用AQS中的 doAcquireNanos 方法
private boolean doAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { if (nanosTimeout <= 0L) return false; final long deadline = System.nanoTime() + nanosTimeout; // 通过系统的当前时间+等待时间 得到截至时间 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 GC failed = false; return true; } nanosTimeout = deadline - System.nanoTime(); // 剩余时间 if (nanosTimeout <= 0L) // 如果剩余时间小于0 ,返回false; return false; if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanosTimeout); // 时间到了,被唤醒后,还有可能会获取到锁,因为for循环中,获取锁的语句排在前面 if (Thread.interrupted()) // 如果线程的中断状态为true, 抛出异常 throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } }
3)调用 LockSupport 中的 parkNanos 方法来 阻塞(挂起)当前线程
public static void parkNanos(Object blocker, long nanos) { if (nanos > 0) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(false, nanos); setBlocker(t, null); } }
lockInterruptibly方法的实现:
与lock不同的地方就在于,这个方法会抛出异常,如果线程的中断状态为true的话。
public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); }
1) AQS中的 acquireInterruptibly方法
public final void acquireInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) // 如果当前线程被中断,抛出异常 throw new InterruptedException(); if (!tryAcquire(arg)) // 如果成功获取到锁,则直接返回; 否则,调用下面的方法 doAcquireInterruptibly(arg); }
2)AQS中的 doAcquireInterruptibly 方法
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 GC failed = false; return; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) // 如果当前线程的中断状态为true,则抛出异常。 throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } }
LockSupport 类:
park 和 unpark 怎么实现的 阻塞(挂起) 和 唤醒 线程。
LockSupport 中的 park 和 unpark 方法,底层都是通过 UNSAFE类来实现的。
park 方法:
public static void park() { UNSAFE.park(false, 0L); }
unpark 方法:
public static void unpark(Thread thread) { if (thread != null) UNSAFE.unpark(thread); }
中断线程 : interrupt
获取到线程中断状态为true后,就抛出异常的目的是什么?
浙公网安备 33010602011771号