【J.U.C】lockInterruptibly与lock

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

文章首发于:clawhub.club


在看LinkedBlockingQueue源码时,发现一点疑惑:
poll(long timeout, TimeUnit unit)方法中通过takeLock.lockInterruptibly()获取锁,
其重载方法poll()中,通过takeLock.lock()获取锁。

通过查看ReentrantLock源码中lockInterruptibly()与lock()方法,解决上述问题。

lock()

lock()调用了抽象类Sync(实现了AQS)的lock()方法,这是一个抽象方法,有两个实现,一个公平锁,一个非公平锁,最终都调用到acquire(int arg)方法,内部处理了中断。
优先考虑获取锁,待获取锁成功后,才响应中断。

     /**
         * 获得锁。
         *
         * 如果锁不被其他线程持有,则获取锁,并立即返回,将锁持有计数设置为1。
         *
         * 如果当前线程已经持有锁,那么持有计数将增加1,方法立即返回。
         *
         * 如果锁由另一个线程持有,则当前线程将出于线程调度目的而禁用,
         * 并处于休眠状态,直到获得锁,此时锁持有计数被设置为1。
         */
        public void lock() {
            sync.lock();
        }
        /**
          * 执行锁。子类化的主要原因是允许非公平版本的快速路径。
        */
        abstract void lock();
        /**
         * 以独占模式获取,忽略中断。通过至少调用一次{@link #tryAcquire}来实现,成功后返回。
         * 否则,线程将排队,可能会反复阻塞和解除阻塞,调用{@link #tryAcquire}直到成功。
         * 此方法可用于实现方法{@link Lock# Lock}。
         *
         * @param arg the acquire argument.  This value is conveyed to
         *        {@link #tryAcquire} but is otherwise uninterpreted and
         *        can represent anything you like.
         */
        public final void acquire(int arg) {
            //tryAcquire(arg) 试图以独占模式获取。这个方法应该查询对象的状态是否允许以独占模式获取它,
            //如果允许,也应该查询是否允许以独占模式获取它。

            //acquireQueued 获取队列中已存在线程的独占不可中断模式。用于条件等待方法以及获取。
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                //中断当前线程。
                selfInterrupt();
        }

lockInterruptibly()

每个线程存在interrupted status,当线程在sleep或wait,join,此时如果别的线程调用此线程的 interrupt()方法,此线程会被唤醒并被要求处理InterruptedException;
如果此线程在运行中,则不会收到提醒。但是此线程的 interrupted status 会被设置,可以通过isInterrupted()查看并作出处理。
lockInterruptibly()方法调用了isInterrupted()方法,如果发现已经被中断,则抛出InterruptedException。

lockInterruptibly()优先考虑响应中断,再去获取锁。

    /**
         * 获取锁,除非线程被打断。
         * 如果锁不被其他线程持有,则获取锁,并立即返回,将锁持有计数设置为1。
         * 如果当前线程已经持有此锁,那么持有计数将增加1,方法立即返回。
         * 如果锁被另一个线程持有,那么当前线程将出于线程调度的目的被禁用,
         * 并处于休眠状态,直到发生以下两种情况之一:
         * 1.锁由当前线程获取。
         * 2.其他线程打断当前线程。
         * 如果锁被当前线程获取,那么锁持有计数被设置为1。
         *
         * 如果当前线程:进入此方法时,其中断状态是否已设置
         * 或者当获取锁时被打断
         * 则会抛出InterruptedException,并清除interrupted status。
         *
         * 在这个实现中,由于这个方法是一个显式的中断点,
         * 所以优先响应中断而不是正常的或可重入的锁获取。
         *
         * @throws InterruptedException if the current thread is interrupted
         */
        public void lockInterruptibly() throws InterruptedException {
            sync.acquireInterruptibly(1);
        }
        /**
         * 以独占模式获取,如果中断将中止。
         * 首先检查中断状态,然后至少调用一次{@link #tryAcquire},成功后返回。
         * 否则,线程将排队,可能反复阻塞和解除阻塞,调用{@link #tryAcquire},直到成功或线程被中断。
         * @param arg the acquire argument.  This value is conveyed to
         *        {@link #tryAcquire} but is otherwise uninterpreted and
         *        can represent anything you like.
         * @throws InterruptedException if the current thread is interrupted
         */
        public final void acquireInterruptibly(int arg)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            if (!tryAcquire(arg))
                doAcquireInterruptibly(arg);
        }

poll(long timeout, TimeUnit unit)方法设计成了多少时间没有获取到锁后,返回,优先相应中断比较合适,
poll()设计成了非阻塞的方法,获取不到直接返回。


来源:https://www.jianshu.com/p/347ea7f881f8

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » 【J.U.C】lockInterruptibly与lock

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏