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操作)。

版权声明:本文为博主原创文章,未经博主允许不得转载。

ReentrantLock的lock-unlock流程详解

在jdk1.5之前,多线程之间的同步是依靠synchronized来实现。synchronized是java的关键字,直接由jvm解释成为指令进行线程同步管理。因为操作简单,而且现在jdk的后续版本已...

Protobuf3 系列一 第一个Java demo

概念 Protocol buffers are a flexible, efficient, automated mechanism for serializing structured da...
  • hry2015
  • hry2015
  • 2017年04月20日 19:57
  • 680

Redis系列二 - 通过redis命令和lua实现分布式锁

概述在分布式系统,如果涉及到对相同资源的操作,则会经常涉及到使用分布锁。Redis为单进程单线程模式,通过Redis的命令SETNX,GET可以方便实现分布式锁。 本文先通过redis命令使用分...
  • hry2015
  • hry2015
  • 2017年07月10日 22:48
  • 605

Java 多线程(2):ReentrantLock以及lock()、lockInterruptibly()之间的区别

请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/dolphin0520/p/3923167.html 在上一篇文章中我们讲到了如何使用关键字synchroni...

java并发编程--AbstractQueuedSynchronizer的lock()和lockInterruptibly()方法分析(五)

lock 与 lockInterruptibly比较区别在于: lock 优先考虑获取锁,待获取锁成功后,才响应中断。 lockInterruptibly 优先考虑响应中断,而不是响应锁的...

java并发包-Reentrantlock(二):tryLock与lockInterruptibly

(本文源代码完全来自openjdk1.8,欢迎对文中内容进行讨论指正)1. lock.lockInterruptibly()上一篇文章揭示了lock.lock()方法的工作原理,它在acquireQu...
  • ToBeNo6
  • ToBeNo6
  • 2017年03月15日 19:06
  • 213

Java进阶知识--Synchronized、Lock、ReentrantLock的区别

最近在看《Java并发编程的艺术》,书中不少知识是更深入的去讲解我们平时经常使用的并发实现机制,介绍了它们的实现原理和区别,读完之后真的有种醍醐灌顶的感觉,突然就好像明白了这些实现到底是干什么用、什么...

lock tryLock lockinterruptibly 区别

ReentrantLock 锁有好几种,除了常用的lock ,tryLock ,其中有个lockInterruptibly 。 1)lock(), 拿不到lock就不罢休,不然线程就一直bl...

【Java并发编程实战】—–“J.U.C”:ReentrantLock之二lock方法分析

前一篇博客简单介绍了ReentrantLock的定义和与synchronized的区别,下面跟随LZ的笔记来扒扒ReentrantLock的lock方法。我们知道ReentrantLock有公平锁、非...

《Java并发编程从入门到精通》显示锁Lock和ReentrantLock

显示锁Lock和ReentrantLock Lock是一个接口提供了无条件的、可轮询的、定时的、可中断的锁获取操作,所有加锁和解锁的方法都是显式的。包路径是:java.util.concurrent...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java并发-ReentrantLock的lock和lockInterruptibly的区别
举报原因:
原因补充:

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