`
qq466862016
  • 浏览: 128399 次
  • 来自: 杭州
社区版块
存档分类
最新评论

Java中ReentrantLock的lock和unlock过程

阅读更多

   NonfairSync锁是重入锁的一种非公平锁,是指尝试获取锁的线程,如果失败则进入AQS锁等待队列中。在ReentaintLock类会默认创建一个非公平锁。

   * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }
 /**
     * Sync object for non-fair locks
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

   1.首先尝试将当前AQS 的state状态由0到1,如果修改成功则表明当前AQS的锁是0,没有别其他占用锁,并设置“ setExclusiveOwnerThread(Thread.currentThread());” 当前线程设置为持有锁的线程。如果设置失败则会调用AQS的 “ acquire(1);”方法。

 

  public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

 

 

 2. accquire(1)方法会调用尝试获得锁失败并且已经加入AQS请求队列中,则会执行线程中断,表明自己已经被加入等待队列中。AQS的tryAcquire(arg)方法会调用NonfairSync中的tryAcquire(int acquires)方法。

 /**
         * Performs non-fair tryLock.  tryAcquire is
         * implemented in subclasses, but both need nonfair
         * try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

 

 

3.首先获取当前线程和当前AQS中的状态(state)。如果AQS状态为0,则尝试一次CAS操作并把当前AQS的state设置为acquires,如果设置成功,则表明当前线程设置为持有锁的线程并返回true。

 

4.如果持有锁的线程是当前线程则将AQS状态值(state)增加acquires,设置成功则返回成功,否则返回失败表明获取锁失败。

5.addWaiter(Node mode)方法是将新建一个新的node添加到队列中,并返回此新建的节点。

  /**
     * Creates and enqueues node for current thread and given mode.
     *
     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
     * @return the new node
     */
    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

  

   6.首先获取当前的队列尾部的节点,如果尾节点不为空,这将新建的节点node添加到尾部节点并执行一次CAS操作将新建的节点设置为tail节点,如果成功则将返回此进行的节点。如果失败,则,执行 enq(node);方法。

   private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                  8.
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

 

7.死循环执行 首先获取tail节点,如果tail节点为空则进行一次CAS设置header节点初始化操作。然后设置tail节点为head节点。否则将新传递的节点设置为tail节点并返回。

8.acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法

    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);
        }
    }

 

9.进入方法是一个死循环 获取当前节点的前一个处理的节点,有且当前节点的前一个处理的节点是head节点并且尝试获取锁成功才返回的。设置head节点为当前节点并返回是中断状态。至此锁过程完毕。

 

二、释放锁

 

1.调用unlock方法进行释放锁实际上调用户AQS的release(arg)方法 如下:

    if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

 2.首先会尝试释放锁,unparkSuccessor(h)方法释放成功后会将唤醒其他等待的线程node进行继续操作。

 3.执行tryRelease(arg)方法如下

protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

  4.首先获取AQS当前状态和要释放数量之差,判断如果当前线程不是当前锁所拥有的线程则会直接抛出异常。

  5.如果之差为0说明完全释放成功。设置当前拥有的线程为空初始化AQS状态为0并返回true状态,否则设置AQS状态并返回false状态。

 

 

 

 

 

 

 

 

 

 

2
0
分享到:
评论

相关推荐

    Java中ReentrantLock的使用.docx

    Java中的ReentrantLock是线程安全编程中的一种高级锁机制,它属于Lock接口的一个实现,提供了比synchronized更丰富的功能和更高的灵活性。ReentrantLock的名字来源于它的可重入性,这意味着一个线程可以多次获取同一...

    java ReentrantLock详解.docx

    对于`ReentrantLock`,可以通过`lock()`和`unlock()`方法控制这一过程。线程在进入同步代码块之前调用`lock()`,退出时调用`unlock()`。由于是手动控制,所以需要注意确保解锁次数与加锁次数一致,否则可能导致死锁...

    Java并发之ReentrantLock类源码解析

    ReentrantLock是Java并发包中的一种同步工具,它可以实现可重入锁的功能。ReentrantLock类的源码分析对理解Java并发机制非常重要。本文将对ReentrantLock类的源码进行详细分析,涵盖ReentrantLock的继承关系、构造...

    java的Lock锁原理详解.docx

    在Java中,有两种主要的锁机制:synchronized和Lock。它们都是用来实现线程同步,防止数据竞争,确保并发环境下的数据一致性。 首先,synchronized是Java的关键字,由JVM直接支持,其底层实现依赖于操作系统原语,...

    java的lock和synchronized的区别.docx

    Java 中的 Lock 和 Synchronized 的区别 Java 语言中有很多相似关键字或相似意义的字,但 lock 和 synchronized 是两个最容易混淆的关键字。它们都是锁的意思,都是为了线程安全性、应用合理性和运行效率的。下面...

    java中的Lock类和Condition类.docx

    Java中的Lock类与Condition类是Java并发编程的重要组成部分,它们为多线程环境下的同步提供了更为灵活和强大的控制。在JDK 1.5及之后的版本中,Lock类作为替代synchronized关键字的一种方式出现,提供了更精细的锁...

    Java多线程之ReentrantLock与Condition - 平凡希 - 博客园1

    Java中的`ReentrantLock`是Java并发包`java.util.concurrent.locks`中的一个高级锁机制,它是可重入的互斥锁,具有与`synchronized`关键字相似的同步性,但提供了更多的灵活性和控制功能。本篇文章将深入探讨`...

    使用ReentrantLock和Lambda表达式让同步更

    6. **更好的异常处理**:`lock()`和`unlock()`方法可以放在`try/finally`块中,确保即使在异常情况下也能正确释放锁。 Lambda表达式是Java 8引入的一项重要特性,它简化了匿名函数的编写,使得代码更加简洁和易读。...

    Java多线程 ReentrantLock互斥锁详解

    在Java中,ReentrantLock是Lock接口的实现类,它提供了加锁和解锁的方法,可以实现线程之间的同步访问资源。 ReentrantLock的主要方法有lock()和unlock(),这两个方法分别用于加锁和解锁。lock()方法用于获取锁,...

    JavaLock与Condition的理解Reentran

    本文将深入探讨JavaLock中的ReentrantLock(可重入锁)以及与其紧密相关的Condition接口,帮助你理解它们的工作原理和应用场景。 **一、ReentrantLock可重入锁** ReentrantLock是Java.util.concurrent.locks包下的...

    java中Locks的使用详解

    * Synchronized Block 只能写在一个方法里面,而 Lock 的 lock() 和 unlock() 可以分别在不同的方法里面。 * Synchronized Block 不支持公平锁,一旦锁被释放,任何线程都有机会获取被释放的锁。使用 Lock APIs 则...

    Java锁机制Lock用法示例

    3. 同步锁Lock (jdk1.5以后) 显示锁:使用Lock接口和其实现类ReentrantLock,需要手动调用lock()和unlock()方法来加锁和释放锁。 在Lock机制中,lock()方法用于加锁,unlock()方法用于释放锁。在使用Lock机制时,...

    java多线程系列(四)ReentrantLock的使用.docx

    本篇文章将深入探讨`ReentrantLock`的使用,它是Java并发包`java.util.concurrent.locks`中的一个高级锁机制,相比传统的`synchronized`关键字,提供了更丰富的功能和更灵活的控制。 `ReentrantLock`全称为可重入锁...

    ReentrantLock与synchronized

    在Java多线程编程中,`ReentrantLock`和`synchronized`都是用于实现线程同步的重要工具,确保在并发环境中数据的一致性和正确性。两者虽然都能实现互斥访问,但在功能、性能以及使用场景上有所不同。下面我们将深入...

    21 更高级的锁—深入解析Lock.pdf

    使用ReentrantLock需要显式地调用lock()和unlock()方法。在尝试获取锁时,应将代码放入try-finally块中,以确保无论发生什么异常,都能正确释放锁。基本用法如下: ```java Lock lock = new ReentrantLock(); lock....

    生产者消费者Java—LOCK机制

    为了确保线程安全和有效率的数据交换,Java提供了多种同步机制,其中包括Lock接口及其实现,如ReentrantLock。本项目通过Lock机制实现了生产者-消费者的解决方案。 Lock接口是Java并发库(java.util.concurrent....

    java ReentrantLock详解

    Java ReentrantLock 是 Java 1.5 中引入的锁机制,相比于传统的 synchronized 锁,它提供了更加灵活和强大的功能。ReentrantLock 是一种可重入锁,意味着同一个线程可以多次获得锁,而不会造成死锁。 ReentrantLock...

Global site tag (gtag.js) - Google Analytics