多线程与高并发(六) Lock

  • 时间:
  • 浏览:1
  • 来源:大发快3_快3app娱乐_大发快3app娱乐

另另1个 学习了咋样使用synchronized关键字来实现同步访问,Java SE 5另另1个 ,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似于于的同步功能,可是在 使用需用用显式地获取和释放锁。确实它缺少了(通过synchronized块机会最好的方法 所提供的)隐式获取释放锁的便捷性,或者却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步底部形态。

不同于synchronized是Java语言的关键字,是内置底部形态,Lock都是Java语言内置的,Lock是另1个 类,通过你这个类可不都还可以实现同步访问。或者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()是用来获取锁的。这八个最好的方法 都是用来获取锁的,那哪些地方地方区别呢?

lock()最好的方法 是平常使用得最多的另1个 最好的方法 ,也前会来获取锁。机会锁已被或者 多程序运行 获取,则进行等待。

tryLock()最好的方法 是有返回值的,它表示用来尝试获取锁,机会获取成功,则返回true,机会获取失败(即锁已被或者 多程序运行 获取),则返回false,也可是你这个最好的方法 无论咋样前会 立即返回。在拿可不都还可以锁时前会老是在那等待。

tryLock(long time, TimeUnit unit)最好的方法 和tryLock()最好的方法 是类似于于的,只不过区别在于你这个最好的方法 在拿可不都还可以锁前会 等待一定的时间,在时间期限之内机会还拿可不都还可以锁,就返回false。机会机会一开始英文拿到锁机会等待期间内拿到了锁,则返回true。

lockInterruptibly()最好的方法 ,当通过你这个最好的方法 去获取锁时,机会多程序运行 正等待获取锁,则你这个多程序运行 可不都还可以响应中断,即中断多程序运行 的等待情况表。也就使说,当另1个 多程序运行 一并通过lock.lockInterruptibly()想获取某个锁时,假如有一天此时多程序运行 A获取到了锁,而多程序运行 B可不都还可以等待,如此对多程序运行 B调用threadB.interrupt()最好的方法 可不都还可以中断多程序运行 B的等待过程。

unLock()最好的方法 是用来释放锁的,这没哪些地方有点儿需用讲的。

Condition newCondition() 是用于获取与lock绑定的等待通知组件,当前多程序运行 需用获得了锁可不都还可以进行等待,进行等待前会 先释放锁,当再次获取锁时可不都还可以从等待中返回。

Lock接口上边的最好的方法 亲戚亲戚亲们机会知道,接下来实现Lock的类ReentrantLock开始英文学起,发现ReentrantLock并如此十十几个 代码,另外有另1个 很明显的特点是:基本上所有的最好的方法 的实现实际上都是调用了其静态内存类Sync中的最好的方法 ,而Sync类继承了AbstractQueuedSynchronizer(AQS)。

亲戚亲戚亲们先学AQS相关的知识

二、AQS

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

子类通过继承并实现它的抽象最好的方法 来管理同步情况表,通过使用getState,setState以及compareAndSetState这另1个 最好的方法 对同步情况表进行更改。子类推荐被定义为自定义同步组件的静态实物类,同步器自身如此实现任何同步接口,它仅仅是定义了若干同步情况表的获取和释放最好的方法 来供自定义同步组件的使用,同步器既支持独占式获取同步情况表,也可不都还可以支持共享式获取同步情况表,另另1个 就可不都还可以方便的实现不类似于于型的同步组件。

同步器是实现锁的关键,要实现锁功能,子类继承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) 独占式的释放同步情况表,该最好的方法 会在释放同步情况表另另1个 ,将同步队列中第另1个 节点所含的多程序运行 唤醒
boolean releaseShared(int arg) 共享式的释放同步情况表
Collection<Thread> getQueuedThreads() 获取等待在同步队列上的多程序运行 集合

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

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

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

  3. 查询同步队列中的等待多程序运行 情况表。

下面看另1个 例子:

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是另1个 自定义同步组件,它在同一时刻只允许另1个 多程序运行 占有锁。Mutex中定义了另1个 静态实物类,该实物类继承了同步器并实现了独占式获取和释放同步情况表。在tryAcquire(int acquires)最好的方法 中,机会经过CAS设置成功(同步情况表设置为1),则代表获取了同步情况表,而在tryRelease(int releases)最好的方法 中可是将同步情况表重置为0。用户使用Mutex时从前会直接和实物同步器的实现打交道,可是调用Mutex提供的最好的方法 ,在Mutex的实现中,以获取锁的lock()最好的方法 为例,只需用在最好的方法 实现中调用同步器的模板最好的方法 acquire(int args)即可,当前多程序运行 调用该最好的方法 获取同步情况表失败前会 被加入到同步队列中等待,另另1个 就大大降低了实现另1个 可靠自定义同步组件的门槛。

2.2 同步队列

同步器依赖实物的同步队列(另1个 FIFO双向队列)来完成同步情况表的管理,当前多程序运行 获取同步情况表失败时,同步器会将当前多程序运行 以及等待情况表等信息构造成为另1个 节点(Node)并将其加入同步队列,同前会 阻塞当前多程序运行 ,当同步情况表释放时,会把首节点中的多程序运行 唤醒,使其再次尝试获取同步情况表。

同步队列中的节点(Node)用来保存获取同步情况表失败的多程序运行 引用、等待情况表以及前驱和后继节点。

volatile int waitStatus //节点情况表
volatile Node prev //当前节点/多程序运行

的前驱节点
volatile Node next; //当前节点/多程序运行

的后继节点
volatile Thread thread;//加入同步队列的多程序运行

引用
Node nextWaiter;//等待队列中的下另1个

节点

看了节点的数据底部形态,知道这是另1个 双向队列,而在AQS中还发生另1个 成员变量:

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

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

通过对源码的理解以及做实验的最好的方法 ,现在亲戚亲戚亲们可不都还可以清楚的知道另另1个 几点:

  1. 节点的数据底部形态,即AQS的静态实物类Node,节点的等待情况表等信息

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

三、 ReentrantLock

重入锁ReentrantLock,顾名思义,可是支持重进入的锁,它表示该锁可不都还可以支持另1个 多程序运行 对资源的重复加锁。除此之外,该锁的还支持获取锁时的公平和非公平性选用。机会另1个 锁不支持可重入,那当另1个 多程序运行 调用它的lock()最好的方法 获取锁另另1个 ,机会再次调用lock()最好的方法 ,则该多程序运行 机会被此人 所阻塞。

synchronized关键字隐式的支持重进入,比如另1个 synchronized修饰的递归最好的方法 ,在最好的方法 执行时,执行多程序运行 在获取了锁另另1个 仍能连续多次地获得该锁。ReentrantLock确实没能像synchronized关键字一样支持隐式的重进入,或者在调用lock()最好的方法 时,机会获取到锁的多程序运行 ,可不都还可以再次调用lock()最好的方法 获取锁而不被阻塞。

3.1 实现可重入性

重进入是指任意多程序运行 在获取到锁另另1个 可不都还可以再次获取该锁而前会被锁所阻塞,该底部形态的实现需用正确处理以下另1个 问题报告 图片。

  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 公平算是公平获取锁的区别

公平锁非公平锁何谓公平性,是针对获取锁而言的,机会另1个 锁是公平的,如此锁的获取顺序就应该符合请求上的绝对时间顺序,满足FIFO,ReentrantLock的构造最好的方法 无参时是构造非公平锁

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

另外还提供了另外三种最好的方法 ,可传入另1个 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的逻辑判断,最好的方法 名就可知道该最好的方法 用来判断当前节点在同步队列中是算是有前驱节点的判断,机会有前驱节点说明有多程序运行 比当前多程序运行 更早的请求资源,根据公平性,当前多程序运行 请求资源失败。机会当前节点如此前驱节点说说,再才有做上边的逻辑判断的必要性。公平锁每次都是从同步队列中的第另1个 节点获取到锁,而非公平性锁则不一定,有机会刚释放锁的多程序运行 能再次获取到锁

公平锁 VS 非公平锁

  1. 公平锁每次获取到锁为同步队列中的第另1个 节点,保证请求资源时间上的绝对顺序,而非公平锁有机会刚释放锁的多程序运行 下次继续获取该锁,则有机会是因为分析或者 多程序运行 永远无法获取到锁,造成“饥饿”问题报告 图片

  2. 公平锁为了保证时间上的绝对顺序,需用频繁的上下文切换,而非公平锁会降低一定的上下文切换,降低性能开销。或者,ReentrantLock默认选用的是非公平锁,则是为了减少一每项上下文切换,保证了系统更大的吞吐量

四、 ReentrantReadWriteLock

另另1个 学到的锁都是独占锁,哪些地方地方锁在同一时刻只允许另1个 多程序运行 进行访问,而读写锁在同一时刻可不都还可以允或者 个读多程序运行 访问,或者在写多程序运行 访问时,所有的读多程序运行 和或者 写多程序运行 均被阻塞。读写锁维护了一对锁,另1个 读锁和另1个 写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升。

除了保证写操作对读操作的可见性以及并发性的提升之外,读写锁可不都还可以复杂性读写交互场景的编程最好的方法 。假设在多多程序运行 中定义另1个 共享的用作缓存数据底部形态,它大每项时间提供读服务(类似于于查询和搜索),而写操作占有的时间很少,或者写操作完成另另1个 的更新需用对后续的读服务可见。

一般情况表下,读写锁的性能前会 比排它锁好,机会大多数场景读是多于写的。在读多于写的情况表下,读写锁可不都还可以提供比排它锁更好的并发性和吞吐量。Java并发包提供读写锁的实现是ReentrantReadWriteLock。

读写锁主要有以下另1个 底部形态:

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

  2. 重入性:支持重入,读锁获取可不都还可以再次获取,写锁获取另另1个 可不都还可以再次获取写锁,一并也可不都还可以获取读锁;

  3. 锁降级:遵循获取写锁,获取读锁再释放写锁的次序,写锁可不都还可以降级成为读锁

4.1 读写锁的使用

ReadWriteLock仅定义了获取读锁和写锁的另1个 最好的方法 ,即readLock()最好的方法 和writeLock()最好的方法 ,而确实现——ReentrantReadWriteLock,除了接口最好的方法 之外,还提供了或者 便于外界监控其实物工作情况表的最好的方法 ,主要有:

int getReadLockCount()//返回当前读锁被获取的次数。该次数不等于获取读锁的多程序运行

数,机会另1个

多程序运行

连续获取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();
    // 获取另1个

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组合另1个 非多程序运行 安全的HashMap作为缓存的实现,一并使用读写锁的读锁和写锁来保证Cache是多程序运行 安全的。在读操作get(String key)最好的方法 中,需用获取读锁,这使得并发访问该最好的方法 时前会被阻塞。写操作put(String key,Object value)最好的方法 和clear()最好的方法 ,在更新HashMap需用用提前获取写锁,当获取写锁后,或者 多程序运行 对于读锁和写锁的获取均被阻塞,而可不都还可以写锁被释放另另1个 ,或者 读写操作可不都还可以继续。Cache使用读写锁提升读操作的并发性,也保证每次写操作对所有的读写操作的可见性,一并复杂性了编程最好的方法 。

4.2 实现原理

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

读写情况表的设计

读写锁同样依赖自定义同步器来实现同步功能,而读写情况表可是其同步器的同步情况表。回想ReentrantLock中自定义同步器的实现,同步情况表表示锁被另1个 多程序运行 重复获取的次数,而读写锁的自定义同步器需用在同步情况表(另1个 整型变量)上维护多个读多程序运行 和另1个 写多程序运行 的情况表,使得该情况表的设计成为读写锁实现的关键。

机会在另1个 整型变量上维护多种情况表,就一定需用“按位切割使用”你这个变量,读写锁将变量切分成了另1个 每项,高16位表示读,低16位表示写,如图:

写锁的获取与释放

写锁是另1个 支持重进入的排它锁。机会当前多程序运行 机会获取了写锁,则增加写情况表。机会当前多程序运行 在获取写锁时,读锁机会被获取(读情况表不为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;
}

读锁的获取与释放

读锁是另1个 支持重进入的共享锁,它可不都还可以被多个多程序运行 一并获取,在如此或者 写多程序运行 访问(机会写情况表为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)。

锁降级

锁降级指的是写锁降级成为读锁。机会当前多程序运行 拥有写锁,或者将其释放,最后再获取读锁,你这个分段完成的过程可不都还可以称之为锁降级。锁降级是指把持住(当前拥有的)写锁,再获取到读锁,以后释放(先前拥有的)写锁的过程。接下来看另1个 锁降级的示例。机会数据不常变化,或者 或者 多个多程序运行 可不都还可以并发地进行数据正确处理,当数据变更后,机会当前多程序运行 感知到数据变化,则进行数据的准备工作,一并或者 正确处理多程序运行 被阻塞,直到当前多程序运行 完成数据的准备工作:

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()最好的方法 的多程序运行 可不都还可以感知到变化,但可不都还可以另1个 多程序运行 可不都还可以获取到写锁,或者 多程序运行 会被阻塞在读锁和写锁的lock()最好的方法 上。当前多程序运行 获取写锁完成数据准备另另1个 ,再获取读锁,以后释放写锁,完成锁降级。

猜你喜欢

【创见 TS500GSJ25M(500G)报价】怎么样

关于大伙 |广告服务|使用条款|联系大伙 北京盛拓优讯信息技术有限公司.版权所有中华人民共和国增值电信业务经营许可证编号:京B2-20170206北京市公安局海淀分局网监中

2019-10-14

你要的共享陪护床厂家和NB锁厂家在这

2019年的共享陪护床行业是NB智能锁的天下,哪里有心智性性性性成熟图片 图片 图片 图片 图片 图片 稳定的共享陪护床厂家和NB智能锁厂家了?怎样才能选泽产品技术

2019-10-14

忆捷 S600 480G SATA

全部参数基本规格移动硬盘容量480G主体品牌忆捷EAGET型号S800外壳颜色金色外壳材质金属颜色金色类型便携式存储,SSD便携固态移动硬盘规格硬盘尺寸2.5英寸容量范围480

2019-10-14

绝地求生称号系统详解 称号系统奖励有哪些

绝地求生官方发布了Beta测试第二赛季的相关内容,其中增加了称号系统玩法,对应都是那末来越多那末来越多奖励机制的更新,下面朋友 来看下具体的介绍吧。Beta测试第二赛季生存称

2019-10-14

“八抬大轿”抬回家的轿子史!

古代的轿子,由辇、舆发展而来,又称为“舆轿”“肩舆”。在先秦时期也称为“桥”“檋”,最初在山路崎岖之地使用,夏禹治水时就曾乘轿过山路。1978年,在河南固始出土的春秋战国墓中发

2019-10-14