多线程与高并发(六) Lock

  • 时间:
  • 浏览:3
  • 来源:大发uu快3_uu快3怎么做代理_大发uu快3怎么做代理

后后学习了怎么里能使用synchronized关键字来实现同步访问,Java SE 5后后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似的同步功能,很多很多在使用时都也能显式地获取和释放锁。着实它缺少了(通过synchronized块否则最好的措施所提供的)隐式获取释放锁的便捷性,否则却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步结构。

不同于synchronized是Java语言的关键字,是内置结构,Lock后后Java语言内置的,Lock是有5个 类,通过什儿 类都也能实现同步访问。否则synchronized同步块执行完成否则遇到异常是锁会自动释放,而lock都也能调用unlock()最好的措施释放锁,否则在finally块中释放锁。

一、 Lock 接口

先看看lock接口定义了那此最好的措施:

void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();

这里面lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()是用来获取锁的。这5个最好的措施后后用来获取锁的,那有那此区别呢?

lock()最好的措施是平常使用得最多的有5个 最好的措施,很多很多用来获取锁。否则锁已被很多很多应用系统进程获取,则进行等待。

tryLock()最好的措施是有返回值的,它表示用来尝试获取锁,否则获取成功,则返回true,否则获取失败(即锁已被很多很多应用系统进程获取),则返回false,也很多很多什儿 最好的措施无论怎么里能后后立即返回。在拿必须锁时不让一个劲在那等待。

tryLock(long time, TimeUnit unit)最好的措施和tryLock()最好的措施是类似的,只不过区别在于什儿 最好的措施在拿必须锁后后等待一定的时间,在时间期限之内否则还拿必须锁,就返回false。否则否则一始于英语 英文拿到锁否则等待期间内拿到了锁,则返回true。

lockInterruptibly()最好的措施,当通过什儿 最好的措施去获取锁时,否则应用系统进程正等待获取锁,则什儿 应用系统进程也能响应中断,即中断应用系统进程的等待请况。也就使说,当有5个 应用系统进程一并通过lock.lockInterruptibly()想获取某个锁时,假若此时应用系统进程A获取到了锁,而应用系统进程B必须等待,必须对应用系统进程B调用threadB.interrupt()最好的措施也能中断应用系统进程B的等待过程。

unLock()最好的措施是用来释放锁的,这没那此有点都也能讲的。

Condition newCondition() 是用于获取与lock绑定的等待通知组件,当前应用系统进程都也能获得了锁也能进行等待,进行等待后后先释放锁,当再次获取锁时也能从等待中返回。

Lock接口里面的最好的措施亲戚亲戚很多很多人否则知道,接下来实现Lock的类ReentrantLock始于英语 英文学起,发现ReentrantLock并必须十几个 代码,另外有有5个 很明显的特点是:基本上所有的最好的措施的实现实际上后后调用了其静态内存类Sync中的最好的措施,而Sync类继承了AbstractQueuedSynchronizer(AQS)。

亲戚亲戚很多很多人先学AQS相关的知识

二、AQS

AQS(以下简称同步器)是用来构建锁和很多很多同步组件的基础框架,它的实现主要依赖有5个 int成员变量来表示同步请况,通过内置的FIFO队列来完成排队工作。

子类通过继承并实现它的抽象最好的措施来管理同步请况,通过使用getState,setState以及compareAndSetState这有5个 最好的措施对同步请况进行更改。子类推荐被定义为自定义同步组件的静态结构类,同步器自身必须实现任何同步接口,它仅仅是定义了若干同步请况的获取和释放最好的措施来供自定义同步组件的使用,同步器既支持独占式获取同步请况,也都也能支持共享式获取同步请况,曾经就都也能方便的实现不类似型的同步组件。

同步器是实现锁的关键,要实现锁功能,子类继承Lock,它定义了使用者与锁交互的接口,就像里面那十几个 接口,否则实现却是通过同步器,同步器错综复杂了锁的实现最好的措施,实现了底层操作,如同步请况管理,应用系统进程的排队,等待和唤醒,而外面使用者去不让关心那此细节。

2.1 同步器的接口

同步器的设计模式是基于模板最好的措施,也很多很多说,使用者要继承同步器并重写指定的最好的措施,后后 将同步器组合在自定义同步器组合定义在自定义同步组件的实现中,并调用同步器提供的模板最好的措施,而那此模板最好的措施否则调用使用者重写的最好的措施。总结很多很多同步器将很多很多最好的措施开放给子类进行重写,而同步器给同步组件所提供模板最好的措施又会重新调用被子类所重写的最好的措施

如在AQS暗含此最好的措施:

protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

而ReentrantLock中重写了最好的措施:

那在AQS中的acquire调用了什儿 最好的措施,这就大约在父类定义了一套模板,那此模板会调用很多很多可重写的最好的措施,那此可重写的最好的措施具体的实现插进了子类。

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

这很多很多模板最好的措施最好的措施的设计思路,如还有疑惑,都也能去学习什儿 设计模式。

下面很多很多很多很多都也能被重写的最好的措施:

最好的措施名称描述
protected boolean tryAcquire(int arg) 独占式获取同步请况,实现该最好的措施都也能查询当前请况并判断同步请况是否符合预期,否则再进行CAS设置同步请况
protected boolean tryRelease(int arg) 独占式释放同步请况,等待获取同步请况的应用系统进程将有否则获取同步请况
protected int tryAcquireShared(int arg) 共享式获取同步请况,返回大于等于0的值,表示获取成功,反之,获取失败
protected boolean tryReleaseShared(int arg) 共享式释放同步请况
protected boolean isHeldExclusively() 当前同步器是否在独占模式下被应用系统进程占用,一般该最好的措施表示是否被当前应用系统进程独占

实现自定义同步组件时,否则调用同步器提供的模板最好的措施,那此(主次)模板最好的措施与描述

最好的措施名称描述
void acquire(int arg) 独占式获取同步请况,否则当前应用系统进程获取同步请况成功,则由该最好的措施返回,否则,否则进入同步队列等待,该最好的措施否则调用重写的tryAcquire(int arg)最好的措施
void acquireInterruptibly(int arg) 与acquire(int arg)相同,否则该最好的措施响应中断,当前应用系统进程未获取到同步请况而进入同步队列中,否则当前应用系统进程被中断,则该最好的措施会抛出InterruptedException并返回
boolean tryAcquireNanos(int arg, long nanosTimeout) 在void acquireInterruptibly(int arg)的基础上增加了超时限制,否则当前应用系统进程在超时时间内必须获取到同步请况,必须否则返回false,否则获取到了返回true
void acquireShared(int arg) 共享式的获取同步请况,否则当前应用系统进程未获取到同步请况,否则进入同步队列等待,与独占式获取的主要区别是在同一时刻都也能有多个应用系统进程获取到同步请况
void acquireSharedInterruptibly(int arg) 与acquireShared(int arg)相同,该最好的措施响应中断
boolean tryAcquireSharedNanos(int arg, long nanosTimeout) 在acquireSharedInterruptibly(int arg)基础上增加了超时限制
boolean release(int arg) 独占式的释放同步请况,该最好的措施会在释放同步请况后后,将同步队列中第有5个 节点暗含的应用系统进程唤醒
boolean releaseShared(int arg) 共享式的释放同步请况
Collection<Thread> getQueuedThreads() 获取等待在同步队列上的应用系统进程集合

同步器提供的模板最好的措施基本上分为3类:

  1. 独占式获取与释放同步请况

  2. 共享式获取与释放同步请况

  3. 查询同步队列中的等待应用系统进程请况。

下面看有5个 例子:

public class Mutex implements Lock {
 private static class Sync extends AbstractQueuedSynchronizer {
    // Reports whether in locked state
    protected boolean isHeldExclusively() {
        return getState() == 1;
    }

    // Acquires the lock if state is zero
    public boolean tryAcquire(int acquires) {
        assert acquires == 1; // Otherwise unused
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }

    // Releases the lock by setting state to zero
    protected boolean tryRelease(int releases) {
        assert releases == 1; // Otherwise unused
        if (getState() == 0) throw new IllegalMonitorStateException();
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
    }

    // Provides a Condition
    Condition newCondition() {
        return new ConditionObject();
    }

    // Deserializes properly
    private void readObject(ObjectInputStream s)
            throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0); // reset to unlocked state
    }
}

private final Sync sync = new Sync();

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

@Override
public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}

@Override
public boolean tryLock() {
    return sync.tryAcquire(1);
}

@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(time));
}

@Override
public void unlock() {
    sync.release(1);
}

@Override
public Condition newCondition() {
    return sync.newCondition();
}
}

什儿 例子中,独占锁Mutex是有5个 自定义同步组件,它在同一时刻只允许有5个 应用系统进程占有锁。Mutex中定义了有5个 静态结构类,该结构类继承了同步器并实现了独占式获取和释放同步请况。在tryAcquire(int acquires)最好的措施中,否则经过CAS设置成功(同步请况设置为1),则代表获取了同步请况,而在tryRelease(int releases)最好的措施中很多很多将同步请况重置为0。用户使用Mutex时不让会直接和结构同步器的实现打交道,很多很多调用Mutex提供的最好的措施,在Mutex的实现中,以获取锁的lock()最好的措施为例,只都也能在最好的措施实现中调用同步器的模板最好的措施acquire(int args)即可,当前应用系统进程调用该最好的措施获取同步请况失败后后被加入到同步队列中等待,曾经就大大降低了实现有5个 可靠自定义同步组件的门槛。

2.2 同步队列

同步器依赖结构的同步队列(有5个 FIFO双向队列)来完成同步请况的管理,当前应用系统进程获取同步请况失败时,同步器会将当前应用系统进程以及等待请况等信息构造成为有5个 节点(Node)并将其加入同步队列,同后后阻塞当前应用系统进程,当同步请况释放时,会把首节点中的应用系统进程唤醒,使其再次尝试获取同步请况。

同步队列中的节点(Node)用来保存获取同步请况失败的应用系统进程引用、等待请况以及前驱和后继节点。

volatile int waitStatus //节点请况
volatile Node prev //当前节点/应用系统进程的前驱节点
volatile Node next; //当前节点/应用系统进程的后继节点
volatile Thread thread;//加入同步队列的应用系统进程引用
Node nextWaiter;//等待队列中的下有5个

节点

看一遍节点的数据结构,知道这是有5个 双向队列,而在AQS中还存在有5个 成员变量:

private transient volatile Node head;
private transient volatile Node tail;

AQS实际上通过头尾指针来管理同步队列,一并实现包括获取锁失败的应用系统进程进行入队,释放锁时对同步队列中的应用系统进程进行通知等核心最好的措施。其示意图如下:

通过对源码的理解以及做实验的最好的措施,现在亲戚亲戚很多很多人都也能清楚的知道曾经几点:

  1. 节点的数据结构,即AQS的静态结构类Node,节点的等待请况等信息

  2. 同步队列是有5个 双向队列,AQS通过持有头尾指针管理同步队列

三、 ReentrantLock

重入锁ReentrantLock,顾名思义,很多很多支持重进入的锁,它表示该锁也能支持有5个 应用系统进程对资源的重复加锁。除此之外,该锁的还支持获取锁时的公平和非公平性取舍。否则有5个 锁不支持可重入,那当有5个 应用系统进程调用它的lock()最好的措施获取锁后后,否则再次调用lock()最好的措施,则该应用系统进程否则被我人及 所阻塞。

synchronized关键字隐式的支持重进入,比如有5个 synchronized修饰的递归最好的措施,在最好的措施执行时,执行应用系统进程在获取了锁后后仍能连续多次地获得该锁。ReentrantLock着实不难 像synchronized关键字一样支持隐式的重进入,否则在调用lock()最好的措施时,否则获取到锁的应用系统进程,也能再次调用lock()最好的措施获取锁而不被阻塞。

3.1 实现可重入性

重进入是指任意应用系统进程在获取到锁后后也能再次获取该锁而不让被锁所阻塞,该结构的实现都也能处置以下有5个 间题。

  1. 应用系统进程再次获取锁。锁都也能去识别获取锁的应用系统进程是否为当前存在锁的应用系统进程,否则是,则再次成功获取。

  2. 锁的最终释放。应用系统进程重复n次获取了锁,后后 在第n次释放该锁后,很多很多应用系统进程也能获取到该锁。锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0时表示锁否则成功释放。

ReentrantLock是通过组合自定义同步器来实现锁的获取与释放,以非公平性(默认的)实现为例

核心最好的措施为nonfairTryAcquire:

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    //1. 否则该锁未被任何应用系统进程占有,该锁能被当前应用系统进程获取
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    //2.若被占有,检查占有应用系统进程是否当前应用系统进程
    else if (current == getExclusiveOwnerThread()) {
        // 3. 再次获取,计数加一
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

该最好的措施增加了再次获取同步请况的处置逻辑:通过判断当前应用系统进程是否为获取锁的应用系统进程来决定获取操作是否成功,否则是获取锁的应用系统进程再次请求,则将同步请况值进行增加并返回true,表示获取同步请况成功。成功获取锁的应用系统进程再次获取锁,很多很多增加了同步请况值,这也就要求ReentrantLock在释放同步请况时减少同步请况值。

protected final boolean tryRelease(int releases) {
    //1. 同步请况减1
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        //2. 必须当同步请况为0时,锁成功被释放,返回true
        free = true;
        setExclusiveOwnerThread(null);
    }
    // 3. 锁未被完整性释放,返回false
    setState(c);
    return free;
}

否则该锁被获取了n次,必须前(n-1)次tryRelease(int releases)最好的措施都也能返回false,而必须同步请况完整性释放了,也能返回true。都也能看一遍,该最好的措施将同步请况是否为0作为最终释放的条件,当同步请况为0时,将占有应用系统进程设置为null,并返回true,表示释放成功。

3.2 公平是否公平获取锁的区别

公平锁非公平锁何谓公平性,是针对获取锁而言的,否则有5个 锁是公平的,必须锁的获取顺序就应该符合请求上的绝对时间顺序,满足FIFO,ReentrantLock的构造最好的措施无参时是构造非公平锁

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

另外还提供了另外三种最好的措施,可传入有5个 boolean值,true时为公平锁,false时为非公平锁

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

在里面非公平锁获取时(nonfairTryAcquire最好的措施)很多很多简单的获取了一下当前请况做了很多很多逻辑处置,并必须考虑到当前同步队列中应用系统进程等待的请况。亲戚亲戚很多很多人来看看公平锁的处置逻辑是怎么里能的,核心最好的措施为:

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

这段代码的逻辑与nonfairTryAcquire基本上一个劲,唯一的不同在于增加了hasQueuedPredecessors的逻辑判断,最好的措施名就可知道该最好的措施用来判断当前节点在同步队列中是否有前驱节点的判断,否则有前驱节点说明有应用系统进程比当前应用系统进程更早的请求资源,根据公平性,当前应用系统进程请求资源失败。否则当前节点必须前驱节点语录,再才有做里面的逻辑判断的必要性。公平锁每次后后从同步队列中的第有5个 节点获取到锁,而非公平性锁则不一定,有否则刚释放锁的应用系统进程能再次获取到锁

公平锁 VS 非公平锁

  1. 公平锁每次获取到锁为同步队列中的第有5个 节点,保证请求资源时间上的绝对顺序,而非公平锁有否则刚释放锁的应用系统进程下次继续获取该锁,则有否则是因为很多很多应用系统进程永远无法获取到锁,造成“饥饿”间题

  2. 公平锁为了保证时间上的绝对顺序,都也能频繁的上下文切换,而非公平锁会降低一定的上下文切换,降低性能开销。否则,ReentrantLock默认取舍的是非公平锁,则是为了减少一主次上下文切换,保证了系统更大的吞吐量

四、 ReentrantReadWriteLock

后后学到的锁后后独占锁,那此锁在同一时刻只允许有5个 应用系统进程进行访问,而读写锁在同一时刻都也能允很多很多个读应用系统进程访问,否则在写应用系统进程访问时,所有的读应用系统进程和很多很多写应用系统进程均被阻塞。读写锁维护了一对锁,有5个 读锁和有5个 写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升。

除了保证写操作对读操作的可见性以及并发性的提升之外,读写锁也能错综复杂读写交互场景的编程最好的措施。假设在应用系统进程中定义有5个 共享的用作缓存数据结构,它大主次时间提供读服务(类似查询和搜索),而写操作占有的时间很少,否则写操作完成后后的更新都也能对后续的读服务可见。

一般请况下,读写锁的性能后后比排它锁好,否则大多数场景读是多于写的。在读多于写的请况下,读写锁也能提供比排它锁更好的并发性和吞吐量。Java并发包提供读写锁的实现是ReentrantReadWriteLock。

读写锁主要有以下有5个 结构:

  1. 公平性取舍:支持非公平性(默认)和公平的锁获取最好的措施,吞吐量还是非公平优于公平;

  2. 重入性:支持重入,读锁获取都也能再次获取,写锁获取后后也能再次获取写锁,一并也也能获取读锁;

  3. 锁降级:遵循获取写锁,获取读锁再释放写锁的次序,写锁也能降级成为读锁

4.1 读写锁的使用

ReadWriteLock仅定义了获取读锁和写锁的有5个 最好的措施,即readLock()最好的措施和writeLock()最好的措施,而着实现——ReentrantReadWriteLock,除了接口最好的措施之外,还提供了很多很多便于外界监控其结构工作请况的最好的措施,主要有:

int getReadLockCount()//返回当前读锁被获取的次数。该次数不等于获取读锁的应用系统进程数,否则有5个

应用系统进程连续获取n次,必须返回的很多很多n
int getReadHoldCount()//返回当前应用系统进程获取读锁的次数
boolean isWriteLocked()//判断写锁是否被获取
int getWriteHoldCount()//返回当前写锁被获取的次数

读写锁使用:

public class Cache {
    static Map<String, Object> map = new HashMap<>();
    static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    static Lock r = reentrantReadWriteLock.readLock();
    static Lock w = reentrantReadWriteLock.writeLock();
    // 获取有5个

key对应的value
    public static final Object get(String key) {
        r.lock();
        try {
            return map.get(key);
        } finally {
            r.unlock();
        }
    }
    // 设置key对应的value,并返回旧的value
    public static final Object put(String key, Object value) {
        w.lock();
        try {
            return map.put(key, value);
        } finally {
            w.unlock();
        }
    }
    // 清空所有的内容
    public static final void clear() {
        w.lock();
        try {
            map.clear();
        } finally {
            w.unlock();
        }
    }
}

Cache组合有5个 非应用系统进程安全的HashMap作为缓存的实现,一并使用读写锁的读锁和写锁来保证Cache是应用系统进程安全的。在读操作get(String key)最好的措施中,都也能获取读锁,这使得并发访问该最好的措施时不让被阻塞。写操作put(String key,Object value)最好的措施和clear()最好的措施,在更新HashMap时都也能提前获取写锁,当获取写锁后,很多很多应用系统进程对于读锁和写锁的获取均被阻塞,而必须写锁被释放后后,很多很多读写操作也能继续。Cache使用读写锁提升读操作的并发性,也保证每次写操作对所有的读写操作的可见性,一并错综复杂了编程最好的措施。

4.2 实现原理

再分析下读写锁的实现原理,主要的内容包括:读写请况的设计,写锁的获取与释放,读锁的获取与释放以及锁降级。

读写请况的设计

读写锁同样依赖自定义同步器来实现同步功能,而读写请况很多很多其同步器的同步请况。回想ReentrantLock中自定义同步器的实现,同步请况表示锁被有5个 应用系统进程重复获取的次数,而读写锁的自定义同步器都也能在同步请况(有5个 整型变量)上维护多个读应用系统进程和有5个 写应用系统进程的请况,使得该请况的设计成为读写锁实现的关键。

否则在有5个 整型变量上维护多种请况,就一定都也能“按位切割使用”什儿 变量,读写锁将变量切分成了有5个 主次,高16位表示读,低16位表示写,如图:

写锁的获取与释放

写锁是有5个 支持重进入的排它锁。否则当前应用系统进程否则获取了写锁,则增加写请况。否则当前应用系统进程在获取写锁时,读锁否则被获取(读请况不为0)否则该应用系统进程后后否则获取写锁的应用系统进程,则当前应用系统进程进入等待请况:

protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    // 1. 获取写锁当前的同步请况
    int c = getState();
    // 2. 获取写锁获取的次数
    int w = exclusiveCount(c);
    if (c != 0) {
        // (Note: if c != 0 and w == 0 then shared count != 0)
        // 3.1 当读锁已被读应用系统进程获取否则当前应用系统进程后后否则获取写锁的应用系统进程语录
        // 当前应用系统进程获取写锁失败
        if (w == 0 || current != getExclusiveOwnerThread())
            return false;
        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        // Reentrant acquire
        // 3.2 当前应用系统进程获取写锁,支持可重复加锁
        setState(c + acquires);
        return true;
    }
    // 3.3 写锁未被任何应用系统进程获取,当前应用系统进程可获取写锁
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false;
    setExclusiveOwnerThread(current);
    return true;
}

写锁的释放与ReentrantLock的释放过程基本类似,每次释放均减少写请况,当写请况为0时表示写锁已被释放,从而等待的读写应用系统进程也能继续访问读写锁,一并前次写应用系统进程的修改对后续读写应用系统进程可见。

protected final boolean tryRelease(int releases) {
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    //1. 同步请况减去写请况
    int nextc = getState() - releases;
    //2. 当前写请况是否为0,为0则释放写锁
    boolean free = exclusiveCount(nextc) == 0;
    if (free)
        setExclusiveOwnerThread(null);
    //3. 不为0则更新同步请况
    setState(nextc);
    return free;
}

读锁的获取与释放

读锁是有5个 支持重进入的共享锁,它也能被多个应用系统进程一并获取,在必须很多很多写应用系统进程访问(否则写请况为0)时,读锁总会被成功地获取,而所做的也很多很多(应用系统进程安全的)增加读请况。否则当前应用系统进程否则获取了读锁,则增加读请况。否则当前应用系统进程在获取读锁时,写锁已被很多很多应用系统进程获取,则进入等待请况。另外否则要增加很多很多结构功能,比如getReadHoldCount()最好的措施,作用是返回当前应用系统进程获取读锁的次数。读请况是所有应用系统进程获取读锁次数的总和,而每个应用系统进程人及 获取读锁的次数必须取舍保存在ThreadLocal中,由应用系统进程自身维护,这使获取读锁的实现变得错综复杂。

protected final int tryAcquireShared(int unused) {
    Thread current = Thread.currentThread();
    int c = getState();
    //1. 否则写锁否则被获取否则获取写锁的应用系统进程后后当前应用系统进程语录,当前
    // 应用系统进程获取读锁失败返回-1
    if (exclusiveCount(c) != 0 &&
        getExclusiveOwnerThread() != current)
        return -1;
    int r = sharedCount(c);
    if (!readerShouldBlock() &&
        r < MAX_COUNT &&
        //2. 当前应用系统进程获取读锁
        compareAndSetState(c, c + SHARED_UNIT)) {
        //3. 下面的代码主很多很多新增的很多很多功能,比如getReadHoldCount()最好的措施
        //返回当前获取读锁的次数
        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;
    }
    //4. 处置在第二步中CAS操作失败的自旋否则实现重入性
    return fullTryAcquireShared(current);
}

读锁的每次释放(应用系统进程安全的,否则有多个读应用系统进程一并释放读锁)均减少读请况,减少的 值是(1<<16)。

锁降级

锁降级指的是写锁降级成为读锁。否则当前应用系统进程拥有写锁,否则将其释放,最后再获取读锁,什儿 分段完成的过程必须称之为锁降级。锁降级是指把持住(当前拥有的)写锁,再获取到读锁,后后 释放(先前拥有的)写锁的过程。接下来看有5个 锁降级的示例。否则数据不常变化,很多很多多个应用系统进程都也能并发地进行数据处置,当数据变更后,否则当前应用系统进程感知到数据变化,则进行数据的准备工作,一并很多很多处置应用系统进程被阻塞,直到当前应用系统进程完成数据的准备工作:

public void processData() {
readLock.lock();
if (!update) {
// 都也能先释放读锁
readLock.unlock();
// 锁降级从写锁获取到始于英语

英文
writeLock.lock();
try {
if (!update) {
// 准备数据的流程(略)
update = true;
}
readLock.lock();
} finally {
writeLock.unlock();
}
// 锁降级完成,写锁降级为读锁
}
try {
// 使用数据的流程(略)
} finally {
readLock.unlock();
}
}

当数据存在变更后,update变量(布尔类型且volatile修饰)被设置为false,此时所有访问processData()最好的措施的应用系统进程都也能感知到变化,但必须有5个 应用系统进程也能获取到写锁,很多很多应用系统进程会被阻塞在读锁和写锁的lock()最好的措施上。当前应用系统进程获取写锁完成数据准备后后,再获取读锁,后后 释放写锁,完成锁降级。