/**
* acquire(int arg):以独占模式获取对象,忽略中断。
acquireInterruptibly(int arg): 以独占模式获取对象,如果被中断则中止。
acquireShared(int arg): 以共享模式获取对象,忽略中断。
acquireSharedInterruptibly(int arg)以共享模式获取对象,如果被中断则中止。
tryAcquire(int arg):试图在独占模式下获取对象状态。
tryAcquireNanos(int arg, long nanosTimeout):试图以独占模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。
tryAcquireShared(int arg):试图在共享模式下获取对象状态。
tryAcquireSharedNanos(int arg, long nanosTimeout):试图以共享模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。
tryAcquire:去尝试获取锁,获取成功则设置锁状态并返回true,否则返回false。
addWaiter:将当前线程加入到CLH队列队尾。
acquireQueued:当前线程会根据公平性原则来进行阻塞等待,直到获取锁为止;并且返回当前线程在等待过程中有没有中断过。
selfInterrupt:产生一个中断。
*/
//请求获取锁,直接使用独占方式来占有锁,不会发生中断
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//试图在独占模式下获取锁,具体的异常实现需要在子类中自己进行实现
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
/**
* 当前线程会根据公平性原则来进行阻塞等待,而且在返回当前线程之前没有发生中断
* @param node
* @param arg
* @return
*/
final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GCreturn interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} catch (RuntimeException ex) {
cancelAcquire(node);
throw ex;
}
/**
* 仅仅直接返回一个异常, 具体的异常信息返回之后根据不同异常信息进行再次封装
*/
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
/**
*尝试获取锁,并判断是否需要挂起,并返回
* @param node
* @param arg
* @return
*/
final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GCreturn interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} catch (RuntimeException ex) {
cancelAcquire(node);
throw ex;
}
}
/**
* 如果在尝试获取锁过程中发生中断,需要调用该中断方法
*/
private static void selfInterrupt() {
Thread.currentThread().interrupt();
}
/**
* AQS释放锁的方法主要有:
release(int arg):以独占模式释放对象。
releaseShared(int arg): 以共享模式释放对象
tryRelease(int arg):试图设置状态来反映独占模式下的一个释放。
tryReleaseShared(int arg):试图设置状态来反映共享模式下的一个释放。
*/
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
//AQS也同样没有提供实现,具体实现方法要其子类自己内部实现,AQS仅仅只是抛出一个异常。
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
//当一个线程加入到CLH队列中时,如果不是头节点是需要判断该节点是否需要挂起;在释放锁后,
需要唤醒该线程的继任节点 lock方法,在调用acquireQueued():
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()){
interrupted = true;
}
//在acquireQueued()中调用parkAndCheckInterrupt()来挂起当前线程:
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
//调用LockSupport.park()方法。对于park():为了线程调度,在许可可用之前禁用当前线程。
//释放锁后,需要唤醒该线程继任节点:
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
//在release方法中调用unparkSuccessor()来唤醒该线程的继任节点。
在unparkSuccessor()方法中通过LockSupport.unpark()来唤醒。
unpark():如果给定线程的许可尚不可用,则使其可用。
//LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。每个使用LockSupport的线程都会与一个许可关联,
如果该许可可用,并且可在进程中使用,则调用park()将会立即返回,否则可能阻塞。如果许可尚不可用,
则可以调用 unpark 使其可用。但是注意许可不可重入,也就是说只能调用一次park()方法,否则会一直阻塞。
//LockSupport.park()、LockSupport.unpark()的作用分别是阻塞线程和解除阻塞线程,且park()和unpark()
不会遇到“Thread.suspend ()和 Thread.resume所可能引发的死锁”问题。当然park()、unpark()是成对使用。
//park():如果许可可用,则使用该许可,并且该调用立即返回;否则,为线程调度禁用当前线程,并在发生以下三种情况之一以前,使其处于休眠状态:
//其他某个线程将当前线程作为目标调用 unpark;或者其他某个线程中断当前线程;或者该调用不合逻辑地(即毫无理由地)返回。
// 一般来说park()、unpark()是成对出现的,同时unpark必须要在park执行之后执行,
当然并不是说没有不调用unpark线程就会一直阻塞,park有一个方法,
它带了时间戳(parkNanos(long nanos):为了线程调度禁用当前线程,
最多等待指定的等待时间,除非许可可用。)
//其源码实现如下:
public static void park() {
unsafe.park(false, 0L);
}
// unpark:如果给定线程的许可尚不可用,则使其可用。如果线程在 park 上受阻塞,则它将解除其阻塞状态。否则,保证下一次调用 park 不会受阻塞。如果给定线程尚未启动,则无法保证此操作有任何效果。
//其源代码如下:
public static void unpark(Thread thread) {
if (thread != null) {
Object lock = unsafe.getObject(thread, lockOffset);
synchronized (lock) {
if (thread.isAlive()) {
unsafe.unpark(thread);
}
}
}
}
Java并发编程--AQS的锁获取和释放
最新推荐文章于 2024-08-05 16:35:43 发布