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

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
分享到:
评论

相关推荐

    locks框架_ReentrantLock.pdf

    这份资源旨在详细讲解 Java 中的 Locks 框架,特别关注 ReentrantLock 的使用和原理。Locks 框架提供了比传统的 synchronized 关键字更强大、更灵活的线程同步机制,而 ReentrantLock 是其中的一种重要实现。 Locks ...

    带你看看Java的锁(一)-ReentrantLock

    带你看看Javad的锁-ReentrantLock前言ReentrantLock简介Synchronized对比用法源码分析代码结构方法分析SyncNonfairSyncFairSync非公平锁VS公平锁什么是公平非公平ReentrantLockReentrantLock的构造函数lock加锁方法...

    locks框架:接口.pdf

    这份资源旨在介绍 Java Locks 框架中的 Lock 接口及其相关内容。Lock 接口是 Locks 框架的核心,提供了更加灵活和可控的线程同步机制,用于替代传统的 synchronized 关键字。 Lock 接口概述: 简要介绍 Lock 接口,...

    Lock锁的底层原理完整版

    Lock锁,一种线程同步机制,其主要功能是防止多个线程同时访问同一代码块,从而避免因并发问题引发的数据不一致或其他错误。...总的来说,Lock锁是Java多线程编程中的重要工具,能够有效保障程序运行的正确性和稳定性。

    rivers-lock:Rivers Lock,是一款轻量级的分布式锁软件,不依赖Zookeeper,redis等第三方

    Rivers Lock Rivers Lock,是一款轻量级的分布式锁软件,不依赖Zookeeper,... ReentrantLock lock = new ReentrantLock(); if(lock.lock("锁名称")) { System.out.println("success"); lock.unLock("锁名称"); }

    petsClinicV6WithThreads

    Реализованочерезjava.util.concurrent.locks.ReentrantLock например: public void add(final Person person) { final ReentrantLock lock = this.lock; lock.lock(); try { ...

    关于synchronized、Lock的深入理解

    目录synchronized的缺陷Lock和ReentrantLock常用方法ReadWriteLock和ReentrantReadWriteLockLock和synchronized区别synchronized锁升级公平锁和非公平锁 synchronized的缺陷 众所周知,synchronized锁是JAVA的关键字...

    去故新 Java线程新同步机制

    Lock lock = new ReentrantLock(); 请求锁,如果锁被当前另一个线程持有,则阻塞。 void lock(); 释放锁 void unlock(); 非阻塞型lock() boolean tryLock(); (2) 使用基本结构 locker.lock(); try{ ...

    java线程池概念.txt

     b:在实际使用中,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一...

    sesvc.exe 阿萨德

    Map 在使用过程中不断的往里面存放数据,当数量达到了 16 * 0.75 = 12 就需要将当前 16 的容量进行扩容,而扩容这个过程涉及到 rehash、复制数据等操作,所以非常消耗性能。 因此通常建议能提前预估 HashMap 的大小...

Global site tag (gtag.js) - Google Analytics