多线程学习(七)---ReentrantLock与ReentrantReadWriteLock

参考文章:

Lock锁子类了解一下

一、ReentrantLock锁

首先我们来看看ReentrantLock锁的顶部注释,来看看他的相关特性:

/**
 * A reentrant mutual exclusion {@link Lock} with the same basic
 * behavior and semantics as the implicit monitor lock accessed using
 * {@code synchronized} methods and statements, but with extended
 * capabilities.
 *

跟synchronized具有相同的功能和语义,都是互斥锁,但它具有更好的扩展性

 * 

A {@code ReentrantLock} is owned by the thread last * successfully locking, but not yet unlocking it. A thread invoking * {@code lock} will return, successfully acquiring the lock, when * the lock is not owned by another thread. The method will return * immediately if the current thread already owns the lock. This can * be checked using methods {@link #isHeldByCurrentThread}, and {@link * #getHoldCount}. *

通过isHeldByCurrentThreadgetHoldCount可以判断当前的线程是否拥有锁

 * 

The constructor for this class accepts an optional * fairness parameter. When set {@code true}, under * contention, locks favor granting access to the longest-waiting * thread. Otherwise this lock does not guarantee any particular * access order. Programs using fair locks accessed by many threads * may display lower overall throughput (i.e., are slower; often much * slower) than those using the default setting, but have smaller * variances in times to obtain locks and guarantee lack of * starvation. Note however, that fairness of locks does not guarantee * fairness of thread scheduling. Thus, one of many threads using a * fair lock may obtain it multiple times in succession while other * active threads are not progressing and not currently holding the * lock.

构造方式支持使用参数来让锁设置为公平锁,公平锁一般的吞吐量会低一点,但一定程度保证了“相对公平”

 * Also note that the untimed {@link #tryLock()} method does not
 * honor the fairness setting. It will succeed if the lock
 * is available even if other threads are waiting.
 *

不计时tryLock方法不符合公平锁的设定

 * 

It is recommended practice to always immediately * follow a call to {@code lock} with a {@code try} block, most * typically in a before/after construction such as: * *

 {@code
 * class X {
 *   private final ReentrantLock lock = new ReentrantLock();
 *   // ...
 *
 *   public void m() {
 *     lock.lock();  // block until condition holds
 *     try {
 *       // ... method body
 *     } finally {
 *       lock.unlock()
 *     }
 *   }
 * }}
*

应该在try代码块之前调用lock()方法

 * 

In addition to implementing the {@link Lock} interface, this * class defines a number of {@code public} and {@code protected} * methods for inspecting the state of the lock. Some of these * methods are only useful for instrumentation and monitoring. *

Lock接口还定义了一些监听锁状态的方法

 * 

Serialization of this class behaves in the same way as built-in * locks: a deserialized lock is in the unlocked state, regardless of * its state when serialized. *

一个被序列化的锁是处于不锁定状态的

 * 

This lock supports a maximum of 2147483647 recursive locks by * the same thread. Attempts to exceed this limit result in * {@link Error} throws from locking methods. * * @since 1.5 * @author Doug Lea */

来总结一下要点吧:

  • 比synchronized更有伸缩性(灵活)
  • 支持公平锁(是相对公平的)
  • 使用时最标准用法是在try之前调用lock方法,在finally代码块释放锁
class X {
    private final ReentrantLock lock = new ReentrantLock();
    // ...

    public void m() { 
        lock.lock();  // block until condition holds
        try {
            // ... method body
        } finally {
            lock.unlock()
        }
    }
}

1.1 内部类

多线程学习(七)---ReentrantLock与ReentrantReadWriteLock_第1张图片
这些内部类都是AQS的子类,这就印证了我们之前所说的:AQS是ReentrantLock的基础,AQS是构建锁、同步器的框架

可以很清晰的看到,ReentrantLock锁是支持公平锁和非公平锁的
多线程学习(七)---ReentrantLock与ReentrantReadWriteLock_第2张图片

1.2 构造方法

/**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    
    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

默认构造的是非同步锁

1.3 非公平lock方法

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

尝试获取锁,获取失败就调用AQS的acquire方法
acquire(1)方法我们在AQS时简单看过,其中tryAcquire()是子类来实现的

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

tryAcquire()方法:

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

1.4 公平lock方法

/**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

多了一个条件:!hasQueuedPredecessors()
这个方法主要是判断当前线程是否位于CLH同步队列中的第一个。如果是则返回flase,否则返回true

public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        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());
    }

1.5 unlock方法

由子类的tryRelease(arg)实现:

/**
     * Attempts to release this lock.
     *
     * 

If the current thread is the holder of this lock then the hold * count is decremented. If the hold count is now zero then the lock * is released. If the current thread is not the holder of this * lock then {@link IllegalMonitorStateException} is thrown. * * @throws IllegalMonitorStateException if the current thread does not * hold this lock */ public void unlock() { sync.release(1); } protected final boolean tryRelease(int releases) { // 减掉releases int c = getState() - releases; // 如果释放的不是持有锁的线程,抛出异常 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; // state == 0 表示已经释放完全了,其他线程可以获取同步状态了 if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }

只有当同步状态彻底释放后该方法才会返回true。当state == 0 时,则将锁持有线程设置为null,free= true,表示释放成功。

二、 ReentrantReadWriteLock

我们知道synchronized内置锁和ReentrantLock都是互斥锁(一次只能有一个线程进入到临界区(被锁定的区域))

而ReentrantReadWriteLock是一个读写锁:

  • 在读取数据的时候,可以多个线程同时进入到到临界区(被锁定的区域)
  • 在写数据的时候,无论是读线程还是写线程都是互斥的

一般来说:我们大多数都是读取数据得多,修改数据得少。所以这个读写锁在这种场景下就很有用了!

读写锁有一个接口ReadWriteLock,定义的方法就两个:

public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     *
     * @return the lock used for reading
     */
    Lock readLock();

    /**
     * Returns the lock used for writing.
     *
     * @return the lock used for writing
     */
    Lock writeLock();
}

看注释:

/**
 * A {@code ReadWriteLock} maintains a pair of associated {@link
 * Lock locks}, one for read-only operations and one for writing.
 * The {@link #readLock read lock} may be held simultaneously by
 * multiple reader threads, so long as there are no writers.  The
 * {@link #writeLock write lock} is exclusive.
 *

维护了一对锁,读锁可同时进入到临界区,写锁是独占的

 * 

All {@code ReadWriteLock} implementations must guarantee that * the memory synchronization effects of {@code writeLock} operations * (as specified in the {@link Lock} interface) also hold with respect * to the associated {@code readLock}. That is, a thread successfully * acquiring the read lock will see all updates made upon previous * release of the write lock. *

读线程可以看到写线程更新过的数据

 * 

A read-write lock allows for a greater level of concurrency in * accessing shared data than that permitted by a mutual exclusion lock. * It exploits the fact that while only a single thread at a time (a * writer thread) can modify the shared data, in many cases any * number of threads can concurrently read the data (hence reader * threads).

只有一个写进程可以修改数据(互斥)
多个读线程并发访问共享数据

 * In theory, the increase in concurrency permitted by the use of a read-write
 * lock will lead to performance improvements over the use of a mutual
 * exclusion lock. In practice this increase in concurrency will only be fully
 * realized on a multi-processor, and then only if the access patterns for
 * the shared data are suitable.
 *

理论上,这种读写锁的并发性是比互斥锁要好的,但还要看计算机的处理器和共享资源适合这种模式才行

 * 

Whether or not a read-write lock will improve performance over the use * of a mutual exclusion lock depends on the frequency that the data is * read compared to being modified, the duration of the read and write * operations, and the contention for the data - that is, the number of * threads that will try to read or write the data at the same time. * For example, a collection that is initially populated with data and * thereafter infrequently modified, while being frequently searched * (such as a directory of some kind) is an ideal candidate for the use of * a read-write lock. However, if updates become frequent then the data * spends most of its time being exclusively locked and there is little, if any * increase in concurrency. Further, if the read operations are too short * the overhead of the read-write lock implementation (which is inherently * more complex than a mutual exclusion lock) can dominate the execution * cost, particularly as many read-write lock implementations still serialize * all threads through a small section of code. Ultimately, only profiling * and measurement will establish whether the use of a read-write lock is * suitable for your application. *

一个集合初始化之后如果常常是查询数据、少量修改数据,那么是适合读写锁的
但是,当修改操作并发增加,那么读写锁的开销大部分又是互斥锁的了

 *
 * 

Although the basic operation of a read-write lock is straight-forward, * there are many policy decisions that an implementation must make, which * may affect the effectiveness of the read-write lock in a given application.

在实现该接口的时候,需要考虑一些策略如下

 * Examples of these policies include:
 * 
    *
  • Determining whether to grant the read lock or the write lock, when * both readers and writers are waiting, at the time that a writer releases * the write lock. Writer preference is common, as writes are expected to be * short and infrequent. Reader preference is less common as it can lead to * lengthy delays for a write if the readers are frequent and long-lived as * expected. Fair, or "in-order" implementations are also possible. * *
  • Determining whether readers that request the read lock while a * reader is active and a writer is waiting, are granted the read lock. * Preference to the reader can delay the writer indefinitely, while * preference to the writer can reduce the potential for concurrency. * *
  • Determining whether the locks are reentrant: can a thread with the * write lock reacquire it? Can it acquire a read lock while holding the * write lock? Is the read lock itself reentrant? * *
  • Can the write lock be downgraded to a read lock without allowing * an intervening writer? Can a read lock be upgraded to a write lock, * in preference to other waiting readers or writers? * *
* You should consider all of these things when evaluating the suitability * of a given implementation for your application. * * @see ReentrantReadWriteLock * @see Lock * @see ReentrantLock * * @since 1.5 * @author Doug Lea */

其实大概也是说明了:在读的时候可以共享,在写的时候是互斥的

接下来我们还是来看看对应的实现类吧:

public class ReentrantReadWriteLock
        implements ReadWriteLock, java.io.Serializable {
    private static final long serialVersionUID = -6992448646407690164L;
    /** Inner class providing readlock */
    private final ReentrantReadWriteLock.ReadLock readerLock;
    /** Inner class providing writelock */
    private final ReentrantReadWriteLock.WriteLock writerLock;
    /** Performs all synchronization mechanics */
    final Sync sync;

注释:

/**
 * An implementation of {@link ReadWriteLock} supporting similar
 * semantics to {@link ReentrantLock}.
 * 

This class has the following properties: *

实现了ReadWriteLock接口,用处跟ReentrantLock类似

 * 
    *
  • Acquisition order * *

    This class does not impose a reader or writer preference * ordering for lock access. However, it does support an optional * fairness policy. *

这个类不会偏好于读锁或者写锁

 * 
*
Non-fair mode (default) *
When constructed as non-fair (the default), the order of entry * to the read and write lock is unspecified, subject to reentrancy * constraints. A nonfair lock that is continuously contended may * indefinitely postpone one or more reader or writer threads, but * will normally have higher throughput than a fair lock. *

默认是非公平锁,吞吐量一般比公平锁高

 * 
Fair mode *
When constructed as fair, threads contend for entry using an * approximately arrival-order policy. When the currently held lock * is released, either the longest-waiting single writer thread will * be assigned the write lock, or if there is a group of reader threads * waiting longer than all waiting writer threads, that group will be * assigned the read lock. *

等待时间最长的写进程将获得写锁

 * 

A thread that tries to acquire a fair read lock (non-reentrantly) * will block if either the write lock is held, or there is a waiting * writer thread. The thread will not acquire the read lock until * after the oldest currently waiting writer thread has acquired and * released the write lock. Of course, if a waiting writer abandons * its wait, leaving one or more reader threads as the longest waiters * in the queue with the write lock free, then those readers will be * assigned the read lock. *

当尝试公平获取读锁时,写锁释放后,读进程才能获取锁

 * 

A thread that tries to acquire a fair write lock (non-reentrantly) * will block unless both the read lock and write lock are free (which * implies there are no waiting threads). (Note that the non-blocking * {@link ReadLock#tryLock()} and {@link WriteLock#tryLock()} methods * do not honor this fair setting and will immediately acquire the lock * if it is possible, regardless of waiting threads.) *

* *

当尝试公平获取写锁时,当前应该处于无锁的状态

 * 
  • Reentrancy * *

    This lock allows both readers and writers to reacquire read or * write locks in the style of a {@link ReentrantLock}. Non-reentrant * readers are not allowed until all write locks held by the writing * thread have been released. *

  • 可重入

     * 

    Additionally, a writer can acquire the read lock, but not * vice-versa. Among other applications, reentrancy can be useful * when write locks are held during calls or callbacks to methods that * perform reads under read locks. If a reader tries to acquire the * write lock it will never succeed. *

    写锁可以获取读锁,读锁不能获取写锁

     * 
  • Lock downgrading *

    Reentrancy also allows downgrading from the write lock to a read lock, * by acquiring the write lock, then the read lock and then releasing the * write lock. However, upgrading from a read lock to the write lock is * not possible. *

  • 写锁可以降级为读锁,读锁不能升级为写锁

     * 
  • Interruption of lock acquisition *

    The read lock and write lock both support interruption during lock * acquisition. *

  • 读锁和写锁都支持在获取时中断

     * 
  • {@link Condition} support *

    The write lock provides a {@link Condition} implementation that * behaves in the same way, with respect to the write lock, as the * {@link Condition} implementation provided by * {@link ReentrantLock#newCondition} does for {@link ReentrantLock}. * This {@link Condition} can, of course, only be used with the write lock. *

  • 写锁支持条件对象

     * 

    The read lock does not support a {@link Condition} and * {@code readLock().newCondition()} throws * {@code UnsupportedOperationException}. *

    读锁不支持条件对象

     * 
  • Instrumentation *

    This class supports methods to determine whether locks * are held or contended. These methods are designed for monitoring * system state, not for synchronization control. * *

  • 该类用于监听锁的状态

     * 

    Serialization of this class behaves in the same way as built-in * locks: a deserialized lock is in the unlocked state, regardless of * its state when serialized. * *

    Sample usages. Here is a code sketch showing how to perform * lock downgrading after updating a cache (exception handling is * particularly tricky when handling multiple locks in a non-nested * fashion): *

    更新缓存后降级的demo

     * 
     {@code
     * class CachedData {
     *   Object 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 = ...
     *           cacheValid = true;
     *         }
     *         // Downgrade by acquiring read lock before releasing write lock
     *         rwl.readLock().lock();
     *       } finally {
     *         rwl.writeLock().unlock(); // Unlock write, still hold read
     *       }
     *     }
     *
     *     try {
     *       use(data);
     *     } finally {
     *       rwl.readLock().unlock();
     *     }
     *   }
     * }}
    * * ReentrantReadWriteLocks can be used to improve concurrency in some * uses of some kinds of Collections. This is typically worthwhile * only when the collections are expected to be large, accessed by * more reader threads than writer threads, and entail operations with * overhead that outweighs synchronization overhead. For example, here * is a class using a TreeMap that is expected to be large and * concurrently accessed. *

    TreeMap使用读写锁提高并发性的Demo

     *  
     {@code
     * class RWDictionary {
     *   private final Map m = new TreeMap();
     *   private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
     *   private final Lock r = rwl.readLock();
     *   private final Lock w = rwl.writeLock();
     *
     *   public Data get(String key) {
     *     r.lock();
     *     try { return m.get(key); }
     *     finally { r.unlock(); }
     *   }
     *   public String[] allKeys() {
     *     r.lock();
     *     try { return m.keySet().toArray(); }
     *     finally { r.unlock(); }
     *   }
     *   public Data put(String key, Data value) {
     *     w.lock();
     *     try { return m.put(key, value); }
     *     finally { w.unlock(); }
     *   }
     *   public void clear() {
     *     w.lock();
     *     try { m.clear(); }
     *     finally { w.unlock(); }
     *   }
     * }}
    * *

    Implementation Notes

    * *

    This lock supports a maximum of 65535 recursive write locks * and 65535 read locks. Attempts to exceed these limits result in * {@link Error} throws from locking methods. * * @since 1.5 * @author Doug Lea */

    于是我们可以总结出读写锁的一些要点了:

    • 读锁不支持条件对象,写锁支持条件对象
    • 读锁不能升级为写锁,写锁可以降级为读锁
    • 读写锁也有公平和非公平模式
    • 读锁支持多个读线程进入临界区,写锁是互斥的

    2.1 ReentrantReadWriteLock内部类

    ReentrantReadWriteLock比ReentrantLock锁多了两个内部类(都是Lock实现)来维护读锁和写锁,但是主体还是使用Syn:

    • WriteLock
    • ReadLock

    多线程学习(七)---ReentrantLock与ReentrantReadWriteLock_第3张图片

    2.2 读锁和写锁的状态表示

    在ReentrantLock锁上使用的是state来表示同步状态(也可以表示重入的次数),而在ReentrantReadWriteLock是这样代表读写状态的:

    /*
             * 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  */
            static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
            /** Returns the number of exclusive holds represented in count  */
            static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
    

    高16位代表独享
    低16位代表共享

    2.3 写锁的获取

    主要还是调用syn的acquire(1)

    /**
             * Acquires the write lock.
             *
             * 

    Acquires the write lock if neither the read nor write lock * are held by another thread * and returns immediately, setting the write lock hold count to * one. * *

    If the current thread already holds the write lock then the * hold count is incremented by one and the method returns * immediately. * *

    If the lock is held by another thread then the current * thread becomes disabled for thread scheduling purposes and * lies dormant until the write lock has been acquired, at which * time the write lock hold count is set to one. */ public void lock() { sync.acquire(1); }

    看实现类:

    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.
                 */
                 // 1. 需要是当前线程和无锁状态才能获取写锁
                 // 2. 锁饱和了也不行
                 // 3. 该线程有资格才能获取写锁
                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;
            }
    

    2.4 读锁获取

    读锁的获取调用的是acquireShared(int arg)方法:

    /**
         * Acquires in shared mode, ignoring interrupts.  Implemented by
         * first invoking at least once {@link #tryAcquireShared},
         * returning on success.  Otherwise the thread is queued, possibly
         * repeatedly blocking and unblocking, invoking {@link
         * #tryAcquireShared} until success.
         *
         * @param arg the acquire argument.  This value is conveyed to
         *        {@link #tryAcquireShared} but is otherwise uninterpreted
         *        and can represent anything you like.
         */
        public final void acquireShared(int arg) {
            if (tryAcquireShared(arg) < 0)
                doAcquireShared(arg);
        }
    

    实现类:

    protected final int tryAcquireShared(int unused) {
                /*
                 * Walkthrough:
                 * 1. If write lock held by another thread, fail.
                另一个线程拥有写锁,失败
                 * 2. Otherwise, this thread is eligible for
                 *    lock wrt state, so ask if it should block
                 *    because of queue policy. If not, try
                 *    to grant by CASing state and updating count.
                 *    Note that step does not check for reentrant
                 *    acquires, which is postponed to full version
                 *    to avoid having to check hold count in
                 *    the more typical non-reentrant case.
                 * 3. If step 2 fails either because thread
                 *    apparently not eligible or CAS fails or count
                 *    saturated, chain to version with full retry loop.
                 */
                Thread current = Thread.currentThread();
                int c = getState();
                // 存在写锁,并且不在本线程
                if (exclusiveCount(c) != 0 &&
                    getExclusiveOwnerThread() != current)
                    return -1;
                int r = sharedCount(c);
                // 设置读锁的状态
                if (!readerShouldBlock() &&
                    r < MAX_COUNT &&
                    compareAndSetState(c, c + SHARED_UNIT)) {
                    if (r == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                        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);
            }
    

    三、 总结

    AQS是ReentrantReadWriteLock和ReentrantLock的基础,因为默认的实现都是在内部类Syn中,而Syn是继承AQS的

    ReentrantReadWriteLock和ReentrantLock都支持公平和非公平模式,公平模式下会去看FIFO队列线程是否是在队头,而非公平模式下是没有的

    ReentrantReadWriteLock是一个读写锁,如果读的线程比写的线程要多很多的话,那可以考虑使用它。它使用state的变量高16位是读锁,低16位是写锁

    写锁可以降级为读锁,读锁不能升级为写锁

    写锁是互斥的,读锁是共享的

    你可能感兴趣的:(多线程)