JAVA------JUC源码探究之Lock

概述

在java多线程同步过程中,除了使用synchronized关键字外,还在java.util.concurrent.lock包中提供了一些手动加锁的类。类关系如下:

 常用的锁----ReentrantLock

   概念

       ReentrantLock类是java提供的给 同步代码块 加锁,保证线程同步的类。主要依赖的原理为volatile+CAS

       有哪些种类?

      ReentrantLock为我们提供了公平锁和非公平锁两种,默认为非公平锁,若要使用公平锁,则只需要在构造函数中加入true即可。

  public ReentrantLock() {
        sync = new NonfairSync();
    }

  public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

怎么用?

下面列出ReetrantLock的基本用法:

package thread.sourcecode;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class T02_Lock {
    ReentrantLock rLock=new ReentrantLock();
    int i=0;
    void  testReentrantLock(){
        //rLock.tryLock();
        rLock.lock();
        i++;
        rLock.unlock();

    }

    public static void main(String[] args) {
        T02_Lock t=new T02_Lock();
        new Thread(t::testReentrantLock,"thread_0").start();
    }

}

代码说明:在i++前,执行tryLock()或者lock()方法(两者存在区别),表示当前线程获得“锁”,执行完i++后,手动释放锁(必须释放),相当于synchronize的同步代码块;

源码分析

   常用方法

//获得锁 
void lock();

//尝试获得锁
boolean tryLock();

//尝试获得锁,并等待一段时间
boolean tryLock(long time, TimeUnit unit);

//尝试获得锁,可以被打断
void lockInterruptibly() throws InterruptedException;

//释放锁
void unlock();

//常见一个condition
Condition newCondition();

lock()

    

                  执行lock()方法,调用Sync中的acquire(1)方法,但是这个是abstract方法,实际上调用的是它的子类的实现方法。

在nofairSync中,首先调用AQS的compareAndSetState()方法,尝试获得“锁”,若成功,则设置当前线程为占有线程,若失败,则调用AQS的acquire()方法,会调用nonfairSync中的tryAcquire(1),并且将当前线程加入等待队列,并将当前线程中断。

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

可以总结出执行流程图 

tryLock()

             调用过程

        执行tryLock()方法,执行Sync的 nonfairTryAcquire(1)方法,源代码如下:

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

可以看出,首先尝试获得锁,若成功,则将当前线程设置为独自占有线程,并返回true;若失败,则判断当前线程是否是占有线程,若是,则继续占有,若不是,则返回失败(false)。

总结执行流程图如下:

 

lockInterruptibly()

使用示例

package thread;


import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class T07_LockInterrupter {
    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            try {
                lock.lock();
                System.out.println("t1 start...");
                TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
            } catch (InterruptedException e) {
                System.out.println("interrupted");
            } finally {
                lock.unlock();
            }
        },"thread-1");
        t1.start();
        Thread t2 = new Thread(() -> {
            try {
//                lock.lock();
                lock.lockInterruptibly();
                System.out.println("t2 start...");
                TimeUnit.SECONDS.sleep(5);
                System.out.println("t2 end...");
            } catch (InterruptedException e) {
                System.out.println("interrupted");
            } finally {
                lock.unlock();
            }
        },"thread-2");
        t2.start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.interrupt();//打断t2线程的等待
    }
}

进入方法内部,调用的sync的acquireInterruptibly(1)方法,而其核心是调动AQS的doAcquireInterruptibly(1)方法,调用流程如下:

 doAcquireInterruptibly方法源代码如下:

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

 简要分析,当当前线程未获取到“锁”时,AQS将其加入等待队列,并且开始无限循环,不断调用tryAcquire()方法,若获得锁,则返回;若未获得锁,且被中断(如main方法中执行t2.interrupt()),则抛出异常,最后取消获取。

执行流程如下:

unlock()

        作用为释放锁,所以必须与lock(),tryLock(),lockInterruptibly()成对使用,即加锁就必须释放锁。

        进入方法,可知调用的是sync的release(1)方法,其核心是调用AQS的tryRelease(1)和unparkSuccessor()方法,调用流程如下:

sync的release()方法源代码如下:

public final boolean release(int arg) {
            //尝试释放锁
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                //唤醒等待队列中的线程获得锁
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

AQS中的tryRelease()方法为abstract方法,实际调用为sync中重写的tryRelease()方法,源代码如下:

protected final boolean tryRelease(int releases) {
            //此处若不为0,则表示当前线程发生重入锁,任然保留锁
            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;
        }

通过源码可分析得执行流程为:

newCondition()

          首先先看下是如何使用

public class T02_Lock { 
  Condition c1=rLock.newCondition();
    Condition c2=rLock.newCondition();
    boolean flag=false;
    void testCondition(){

       new Thread(()->{
            rLock.lock();
            try {
                while (!flag){
                    System.out.println(Thread.currentThread().getName()+":我艹,搞不定啊");
                    c2.signal();
                    c1.await();

                }
                System.out.println(Thread.currentThread().getName()+":劳资又回来了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                rLock.unlock();
            }

       },"thread-1").start();

       new Thread(()->{
           rLock.lock();
           try{
               flag=true;
               System.out.println(Thread.currentThread().getName()+":去吧,皮卡丘");
               c1.signal();
               c2.await();

           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       },"thread-2").start();
    }

    public static void main(String[] args) {
        T02_Lock t=new T02_Lock();   
        t.testCondition();
    }
}

输出结果:

 

当中的Condition直译过来是“状况”,可以理解为:“一系列相同的状况”。

 通过查看源码可知,调用newCondition()方法,实际是调用sync的newCondition()方法,并创建一个ConditionObject对象,源代码如下:

final ConditionObject newCondition() {
            return new ConditionObject();
        }

查看ConditionObject实现,它是AQS中的一个内部类,并且是Condition接口的一个实现。里面包含了Node链表,也就是说一个Condition维护了一个等待队列。执行asingal()和await()方法时,能够指定哪个等待队列被唤醒或者等待。

总结

      lock()和tryLock()的区别:lock()请求获取锁,若失败,会进入等待队列,直到获取成功;tryLock()请求获取锁,若失败,直接返回false。这也导致使用上有些许不一样

     void test2(){
        System.out.println("thread2 begin ....");
        rLock.lock();
        System.out.println("thread2 getLock ....");
        rLock.unlock();
        System.out.println("thread2 end ....");
    }

     void test3(){
         boolean locked=rLock.tryLock();
        try
        {
            i++;
        }finally {
            if(locked)rLock.unlock();
        }
     }

  


读写锁----ReetrantReadWriteLock

  概念

是什么?

ReetrantReadWriteLock是ReadWriteLock的一个实现类,

ReadWriteLock是什么?

ReadWriteLock是java.util.concurrent.lock包中的一个接口,其中包含了一对方法,分别返回一个锁,一个读锁(read),一个写锁(write),两个锁相互关联。

性质:

  • 只读锁,可以多个“读”线程共享;
  • 写锁,只能一个“写”线程独占;
  • 当write被锁时,或者此时仍有线程等待write,read不能被获取(当数据被“写/修改”时,不允许读取);
  • 当read,write未被锁时,write才能被获取(当数据当前即没有被读取,也没有被修改时,才允许修改);
  • write锁可以降级为read锁(修改完以后可以立马读取);

意义:

在reetractLock中,每次只允许一个线程对共享数据独占访问。而当大多线程只是对数据进行读取,而不进行修改时,则会降低效率,故设计出读写锁,运行多个“只读”线程同时访问共享数据。因此应用场景大多为对数据“读”的概率要远大于“写”的概率,这样能大大提高程序的并发量。

  使用示例

public class T03_ReadWriteLock {
    String data;
    volatile boolean cacheValid;
    final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

    void processCachedData() {
        rwl.readLock().lock();
        if (!cacheValid) {
            // Must release read lock before acquiring write lock
            rwl.readLock().unlock();
            rwl.writeLock().lock();
            try {
                // Recheck state because another thread might have
                // acquired write lock and changed state before we did.
                if (!cacheValid) {
                    data = "Hello ";
                    cacheValid = true;
                }
                // Downgrade by acquiring read lock before releasing write lock
                rwl.readLock().lock();
            } finally {
                rwl.writeLock().unlock(); // Unlock write, still hold read
            }
        }

        try {
            System.out.println(data);
        } finally {
            rwl.readLock().unlock();
        }
    }

    public static void main(String[] args) {
        T03_ReadWriteLock t=new T03_ReadWriteLock();
        t.processCachedData();
    }

 在上述代码中,先获取读锁 rwl.readLock().lock(),在而后对缓存数据进行操作,在获取写锁之前,必须将读锁释放,否则写锁无法获取。期间当前线程未释放写锁,就开始请求读锁,此时是锁降级,最后分别将写锁,读锁关闭。

锁降级过程

  源码分析

       分析源码,相关类依赖如下:

ReetranReadWriteLock主要依赖于AQS,Sync及其具体实现。在源码中我们可以看到,整个ReetranReadWriteLock的锁状态是由AQS中的state维护,它是一个32位的int,而在读写锁中这一个int需要维护两个锁的不同状态。故将state分为两部分,通过两部分的值分别保存两个锁的状态。分析源码可知,它是将一个32位的int数字划分为两个16位的short,前16位保存持有read锁的线程数(sharedCount),后16位保存写锁的线程重入数(exclusiveCount)。当两个为0时,表示当前锁空闲。当其中一个大于0,表示其对应的锁已被占用。

     

源代码如下:

  
        /*
         * Read vs write count extraction constants and functions.
         * Lock state is logically divided into two unsigned shorts:
         * The lower one representing the exclusive (writer) lock hold count,
         * and the upper the shared (reader) hold count.
         */

        static final int SHARED_SHIFT   = 16;
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        //最大共享线程量
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        /** Returns the number of shared holds represented in count 
            取state的前16位 */
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
        /** Returns the number of exclusive holds represented in count 
            取state的后16位 */
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

   Sync中有两个抽象方法,由其继承类具体实现,两个方法为:

        abstract boolean readerShouldBlock();

        abstract boolean writerShouldBlock();

 其功能为:当有别的线程也在尝试获取锁时,是否应该阻塞。

这个依赖于具体的实现机制,即当前读写锁是公平锁,还是非公平锁。其具体实现如下:

公平锁:方法表示前面是否有等待线程,那么为了遵循公平,当前线程也就应该被挂起。 

 final boolean writerShouldBlock() {  return hasQueuedPredecessors();}
 final boolean readerShouldBlock() {  return hasQueuedPredecessors();}

  依赖的是AQS中的hasQueuedPredecessors()方法,具体实现如下

  public final boolean hasQueuedPredecessors() {
        // 当前等待队列中是否有等待的线程
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

非公平锁

   先来看具体实现的源码:

        final boolean writerShouldBlock() {
            return false; // writers can always barge
        }
        final boolean readerShouldBlock() {
            /* As a heuristic to avoid indefinite writer starvation,
             * block if the thread that momentarily appears to be head
             * of queue, if one exists, is a waiting writer.  This is
             * only a probabilistic effect since a new reader will not
             * block if there is a waiting writer behind other enabled
             * readers that have not yet drained from the queue.
             */
              //查看当前等待队列中的第一个线程是不是独占线程(写线程),若是,则返回true
            return apparentlyFirstQueuedIsExclusive();
        }

从源码中可以看到,在writerShouldBlock()方法中,直接返回false,表示不需要阻塞;在readerShouldBlock()中,以来的是AQS的apparentlyFirstQueuedIsExclusive()方法,看一下具体实现:

     final boolean apparentlyFirstQueuedIsExclusive() {
        Node h, s;
        return (h = head) != null &&
            (s = h.next)  != null &&
            !s.isShared()         &&
            s.thread != null;
    

从源码可知,判断当前等待队列中头结点的下一个节点线程是否是独占线程,若是,返回true。

由上述可总结读写锁阻塞机制如下:

   公平锁:不管是读锁,还是写锁,都先排队(前面有线程等待才排队)。(保证公平机制)

   非公平锁:写锁:直接先尝试获取,无需等待,若获取失败,在进入队列中等待。

                    读锁:先判断当前等待队列中第一个等待的是不是请求写锁 的,若是,则进入队列等待,若不是,则尝试获取。                                   (为了防止写锁长时间不被获取,写线程得不到执行的机会)

 

常用方法

     读锁获取-----readLock.lock()

  public void lock() {
            sync.acquireShared(1);
        }
 
 public final void acquireShared(int arg) {
        //尝试获取锁,返回0表示失败
        if (tryAcquireShared(arg) < 0)
        //进入等待队列
            doAcquireShared(arg);
    }

 通过源码,我们可以得知,lock()方法逻辑为:首先调用tryAcquireShared()方法,尝试获取锁,若失败,调用doAcquireShared()进入等待队列,两个方法源代码如下:


 protected final int tryAcquireShared(int unused) {
          
            Thread current = Thread.currentThread();
            int c = getState();
             //若当前有独占线程(写锁是否被占用),且当前非重入,则直接返回失败
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return -1;
              //获取当前读锁的共享数量
            int r = sharedCount(c);
             
              //判断当前是否应阻塞(与具体锁(公平/非公平)有关)         
            if (!readerShouldBlock() &&
              //当前共享数量小于最大共享数
                r < MAX_COUNT &&
              //更新AQS中state状态成功
                compareAndSetState(c, c + SHARED_UNIT)) {
                if (r == 0) {       
                    //当前线程为第一个线程,锁状态为free            
                    firstReader = current;
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {  
                    //当前线程为第一个线程的重入               
                    firstReaderHoldCount++;
                } else {
                    //给当前线程设置HoldCounter,重入计数更新
                    HoldCounter rh = cachedHoldCounter;
                    if (rh == null || rh.tid != getThreadId(current))
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        readHolds.set(rh);
                    rh.count++;
                }
                return 1;
            }
            //若失败,则放入循环
            return fullTryAcquireShared(current);
        }
 

 分析源码可知Sync尝试获取读锁机制如下:

  1. 若此时写锁被锁被占有,且独占线程非当前线程,则获取失败;
  2. 写锁空闲,则由 公平机制 判断当前读线程是否应该阻塞,若不阻塞,则当前读锁共享数不得大于最大共享数,AQS更新锁状态成功,此时可获得读锁
  3. 其他情况下,均进入循环体fullTryAcquireShared(),等待获取。

fullTryAcquireShared()源代码如下:

final int fullTryAcquireShared(Thread current) {
            HoldCounter rh = null;
            for (;;) {
                int c = getState();
                if (exclusiveCount(c) != 0) {
                    if (getExclusiveOwnerThread() != current)
                        return -1;
                     //若当前线程已经占有写锁,应当给予通过,不应阻塞,否则会造成死锁           
                } else if (readerShouldBlock()) {
                    // Make sure we're not acquiring read lock reentrantly
                    if (firstReader == current) {
                    } else {
                        if (rh == null) {
                            rh = cachedHoldCounter;
                            if (rh == null || rh.tid != getThreadId(current)) {
                                rh = readHolds.get();
                                if (rh.count == 0)
                                    readHolds.remove();
                            }
                        }

                        if (rh.count == 0)
                            return -1;
                    }
                }
                if (sharedCount(c) == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                if (compareAndSetState(c, c + SHARED_UNIT)) {
                    if (sharedCount(c) == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                        if (rh == null)
                            rh = cachedHoldCounter;
                        if (rh == null || rh.tid != getThreadId(current))
                            rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        rh.count++;
                        cachedHoldCounter = rh; // cache for release
                    }
                    return 1;
                }
            }
        }

阅读上面源码可以发现,代码和 doAcquireShared()方法有很相似,循环的判断当前是否满足条件,直到返回成功或失败。当获取锁失败时,调用doAcquireShared()方法,源代码如下:

private void doAcquireShared(int arg) {
        final Node node = addWaiter(Node.SHARED);//加入等待队列
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();//获取前继节点
                if (p == head) {//当前继节点为头结点,此时当前线程位于等待队列的第一个,有机会获取锁
                    int r = tryAcquireShared(arg);//再次尝试获取锁
                    if (r >= 0) {//获取锁成功
                        setHeadAndPropagate(node, r);//重新设置等待队列节点,并唤醒后面等待获取readlock的线程
                        p.next = null; // help GC
                        if (interrupted)//等待过程中被中断
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;//被中断
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

分析源码可知,执行流程是在一个循环体内死循环,不断尝试获取锁,直到成功获取或被中断。

读锁获取流程图总结图如下:

        

读锁 释放----readLock.unlock()

首先查看源代码如下:

    public void unlock() {
            sync.releaseShared(1);
        }
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {//释放锁
            doReleaseShared();//成功则唤醒队列等待线程
            return true;
        }
        return false;
    }

可知,调用的是tryReleaseShared(1),对源码进行分析:

       protected final boolean tryReleaseShared(int unused) {
            Thread current = Thread.currentThread();
            //清理firstReader中缓存
            if (firstReader == current) {
                // assert firstReaderHoldCount > 0;
                if (firstReaderHoldCount == 1)
                    firstReader = null;
                else
                    firstReaderHoldCount--;
            } else {
            //清理HoldCounter中的重入计数
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != getThreadId(current))
                    rh = readHolds.get();
                int count = rh.count;
                if (count <= 1) {
                    readHolds.remove();
                    if (count <= 0)
                        throw unmatchedUnlockException();
                }
                --rh.count;
            }
            for (;;) {
               // 更新state值
                int c = getState();
                int nextc = c - SHARED_UNIT;
                if (compareAndSetState(c, nextc))             
                    return nextc == 0;
            }
        }

tryReleaseShared()方法最核心部分为for中的死循环,本质是更新state状态,将共享数量减1;而上半部分的功能为将缓存以及其记录信息删除或者更新。

 写锁 获取----writeLock.lock()

public void lock() {
            sync.acquire(1);
        }

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

由源代码可知,writeLock.lock()方法与上述reetranctLock的lock()方法的步骤一样,都是调用Sync的acquire()方法。但是这是个抽象方法,由具体子类实现。代码如下:

protected final boolean tryAcquire(int acquires) {
            /*
             * Walkthrough:
             * 1. If read count nonzero or write count nonzero
             *    and owner is a different thread, fail.
             * 2. If count would saturate, fail. (This can only
             *    happen if count is already nonzero.)
             * 3. Otherwise, this thread is eligible for lock if
             *    it is either a reentrant acquire or
             *    queue policy allows it. If so, update state
             *    and set owner.
             */
            Thread current = Thread.currentThread();
            int c = getState();
            int w = exclusiveCount(c);
            //当前锁为非空闲状态
            if (c != 0) {
                // (Note: if c != 0 and w == 0 then shared count != 0)
                //此时读锁被获取,写锁空闲||当前独占锁线程非当前线程,返回失败
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                //写锁线程数超过最大独占线程数 ,写锁获取失败,抛出异常
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // Reentrant acquire
                //更新锁状态
                setState(c + acquires);
                return true;
            }
             //根据公平机制,当前是否需要阻塞
            if (writerShouldBlock() ||
             //获取锁,更新锁状态
                !compareAndSetState(c, c + acquires))
                return false;
              //将当前线程设为独占线程
            setExclusiveOwnerThread(current);
            return true;
        }

执行过程:若当前读锁被占用,或当前独占线程非当前线程,获取失败; 写锁线程超过最大线程   获取失败;根据公平机制,当前线程需要阻塞等待,获取失败;更新state状态失败,获取失败,否则获取成功,并将当前线程置为独占线程。

写锁 释放-----writeLock.unlock()

 public void unlock() {
            sync.release(1);
        }
 public final boolean release(int arg) {
        if (tryRelease(arg)) {//释放锁
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);//唤醒等待线程
            return true;
        }
        return false;
    }

与reentractLock.unlock()方法一样,都是调用Sync.release()方法,方法逻辑与reentractLock.unlock()一样,但是tryRelease()方法由具体子类实现。源代码如下:

  protected final boolean tryRelease(int releases) {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            int nextc = getState() - releases;
            boolean free = exclusiveCount(nextc) == 0;//更新独占线程数
            if (free)
                setExclusiveOwnerThread(null);//将当前独占线程置为null
            setState(nextc);//更新state状态
            return free;
        }

总结

  公平锁和非公平锁: 公平锁先排队,在获取“锁”;非公平锁只有当前获取读锁,且第一个等待的线程是获取“写”锁,才排队,情                                      况,都先尝试获取,获取失败才排队;                                                                                                            读锁获取:在等待队列中成功获取到读锁后,会依次唤醒后面与他一起共享当前读锁的线程。


 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值