java并发-ReentrantLock的lock和lockInterruptibly的区别

原创 2015年01月04日 09:54:36

       ReentrantLock的加锁方法Lock()提供了无条件地轮询获取锁的方式,lockInterruptibly()提供了可中断的锁获取方式。这两个方法的区别在哪里呢?通过分析源码可以知道lock方法默认处理了中断请求,一旦监测到中断状态,则中断当前线程;而lockInterruptibly()则直接抛出中断异常,由上层调用者区去处理中断。

      1  lock操作

         lock获取锁过程中,忽略了中断,在成功获取锁之后,再根据中断标识处理中断,即selfInterrupt中断自己。 acquire操作源码如下:

    /**
      *默认处理中断方式是selfInterrupt
     */
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
      acquireQueued,在for循环中无条件重试获取锁,直到成功获取锁,同时返回线程中断状态。该方法通过for循正常返回时,必定是成功获取到了锁。

    /**
     *无条件重试,直到成功返回,并且记录中断状态
     */
    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) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

    2 lockInterruptibly操作

     可中断加锁,即在锁获取过程中不处理中断状态,而是直接抛出中断异常,由上层调用者处理中断。源码细微差别在于锁获取这部分代码,这个方法与acquireQueue差别在于方法的返回途径有两种,一种是for循环结束,正常获取到锁;另一种是线程被唤醒后检测到中断请求,则立即抛出中断异常,该操作导致方法结束。

/**
     * Acquires in exclusive interruptible mode.
     * @param arg the acquire argument
     */
    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())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

     结论:ReentrantLock的中断和非中断加锁模式的区别在于:线程尝试获取锁操作失败后,在等待过程中,如果该线程被其他线程中断了,它是如何响应中断请求的。lock方法会忽略中断请求,继续获取锁直到成功;而lockInterruptibly则直接抛出中断异常来立即响应中断,由上层调用者处理中断。

     那么,为什么要分为这两种模式呢?这两种加锁方式分别适用于什么场合呢?根据它们的实现语义来理解,我认为lock()适用于锁获取操作不受中断影响的情况,此时可以忽略中断请求正常执行加锁操作,因为该操作仅仅记录了中断状态(通过Thread.currentThread().interrupt()操作,只是恢复了中断状态为true,并没有对中断进行响应)。如果要求被中断线程不能参与锁的竞争操作,则此时应该使用lockInterruptibly方法,一旦检测到中断请求,立即返回不再参与锁的竞争并且取消锁获取操作(即finally中的cancelAcquire操作)。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wojiushiwo945you/article/details/42387091

lock()与lockInterruptibly()的区别

lock 与 lockInterruptibly比较区别在于: lock 优先考虑获取锁,待获取锁成功后,才响应中断。 lockInterruptibly 优先考虑响应中断,而不是响应锁的普通获取...
  • yyd19921214
  • yyd19921214
  • 2015-11-09 12:45:09
  • 3190

lockInterruptibly 和lock的区别

lockInterruptibly 与 lock比较区别在于  lockInterruptibly 优先考虑响应中断,而不是响应锁定的普通获取或重入获取  Java代码   ...
  • woaieillen
  • woaieillen
  • 2012-10-08 09:20:01
  • 12432

ReentrantLock中lock/trylock/lockInterruptibly方法的区别及源码解析

看了几篇关于这三者区别的文章,但都说的不够具体,自己去读了下源码,大概是清楚了三者的功能。 首先,ReentrantLock类中使用了大量的CAS操作,也就是CompareAndSwap原子操作,依靠...
  • yangcheng33
  • yangcheng33
  • 2015-08-16 22:45:49
  • 4047

关于lock.lockInterruptibly()方法和java.lang.IllegalMonitorStateException异常

在看java集合源码时,发现一些并发集合中加锁的方式有的是lock.lock(),有的是lock.lockInterruptibly()形式,不是很清楚其中的区别,故搜了一些资料,写了自己的理解。AP...
  • youyou1543724847
  • youyou1543724847
  • 2016-08-10 18:12:46
  • 2684

分析ReentrantLock之lockInterruptibly

ReentrantLock代码剖析之ReentrantLock.lockInterruptibly ReentrantLock.lockInterruptibly允许在等待时由其它线程调用等待线...
  • bozige
  • bozige
  • 2015-07-15 18:03:06
  • 286

《Java并发编程实战》读书笔记四:活跃性和性能,死锁和显示锁

博文目录一、活跃性危险:死锁 - 1.锁顺序死锁 - 2.动态锁顺序死锁 - 3.协作对象之间的死锁 - 4.死锁的避免与分析 - 5.其它活跃性危险二、性能和可伸缩性 - 1.使用线程的...
  • jeffleo
  • jeffleo
  • 2016-12-27 11:45:17
  • 528

Lock的lockInterruptibly()

概述 lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果其他线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lo...
  • zengmingen
  • zengmingen
  • 2016-11-21 16:52:44
  • 195

Java中Lock,tryLock,lockInterruptibly有什么区别?

ReentrantLock 锁有好几种,除了常用的lock ,tryLock ,其中有个lockInterruptibly 。 先把API粘贴上来 lock public void lock() 获...
  • W1025514023
  • W1025514023
  • 2017-04-15 21:05:47
  • 1174

Java 7之多线程第12篇 - CountDownLatch

CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 来看一下这个类的构造方法,如下: public CountDownLatch(i...
  • mazhimazh
  • mazhimazh
  • 2014-02-14 09:37:09
  • 2328

java并发锁ReentrantLock源码分析一 可重入支持中断锁的实现原理

本文深入分析了Java可重入、支持中断锁ReentrantLock的实现原理,重点讲解了lock,unlock,lockInterupbilty方法的实现方式,并给出详细的流程图。并提出如下观点: 1...
  • prestigeding
  • prestigeding
  • 2016-11-08 17:40:51
  • 3112
收藏助手
不良信息举报
您举报文章:java并发-ReentrantLock的lock和lockInterruptibly的区别
举报原因:
原因补充:

(最多只允许输入30个字)