`
suichangkele
  • 浏览: 193250 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

lock与lock.lockInterruptibly源码解读

    博客分类:
  • java
阅读更多

f双方都

在重入锁(ReentrantLock)中,有两个相似的方法,一个是lock,一个是lockInterruptably,之前没有细看,之前我一直用的是lock,不过最近再看公司的代码时,发现有人竟然用的是后者,于是我就好奇了,特么的到底哪里不一样,于是跟了下源码,特此记录一下。(ReentrantLock使用aqs实现的,最好先看懂aqs再来搞重入锁)。

再lock中,最终调用的是:java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(int)方法,

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&//尝试获得锁,失败时返回false
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))//入队列,然后挂起线程,我们重点看一下这个方法
            selfInterrupt();
    }

挂起线程的方法

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) &&//判断是否应该park
                    parkAndCheckInterrupt())//park当前的线程
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
}

 挂起当前的线程的代码,在挂起一定时间后,返回的是当前的线程是否有interruptted的状态

private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}

 从上面的代码可以看出,如果某个线程在等待锁的时候别interrupt了,那么在获得锁之后,就会在acquireQueued方法中返回true,然后我们回到acquire中,在上面的parkAndCheckInterrupt方法返回true之后(也就是当前的线程是被interrupt了),就会进入selfInterrupt方法,里面很简单,就一句

private static void selfInterrupt() {
   Thread.currentThread().interrupt();//自己调用interrupt方法,但是这样不会有任何的作用,也就是直接忽略了在等待的时候别的线程对当前线程的interrupt操作。
}

 从上面的分析中,我们得到结论,lock方法中会忽略在当前线程被park的时候其他线程堆当前线程的interrupt方法,不会有任何操作。

 

我们再分析一下,lockInterruptably方法,他在尝试获取锁失败后,会进入这个方法:

    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())//从上面的代码分析中,我们已经知道了,当当前的线程在park之后,如果当前的线程被interrupt之后,就会返回true,那么就会进入if,即抛出一个interruptedException。
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

 从上面的分析中,我们便知道了,lockInterruptably,会在park之后,抛出一个异常,这就是区别

 

so easy!!!

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics