• 读写锁的一些错误记忆修正


    1.先以一段代码为例

    ReadWriteLock rwLock = new ReentrantReadWriteLock();
    
    // rwLock.readLock()是获取rwLock里的一个属性而非new
    // 这句代码的意思是给rwLock加读锁,而不应该理解为给rwLock.readLock()的返回值加锁
    // 这点Go比java好,go里读写锁就是提供四个方法,而java里拆成两个属性来提供让人误解
    rwLock.readLock().lock();

    2.读写锁对象里的读锁属性rwLock.readLock()和写锁属性rwLock.writeLock()里加锁或者释放锁都是针对rwLock的而非针对其读锁属性或写锁属性;

    3.之前有个错误的记忆,就是读写锁rwLock如果加了读锁后,加写锁会被阻塞,此时再给rwLock加读锁是不会成功的,这个记忆是错误的;rwLock只要当前状态是已经被加了读锁状态,不管此时是否存在某个线程要给rwLock加写锁(会被阻塞)

    ,再给它加读锁都是成功的;

    4.每次加锁都会保存一个锁数据,这个锁数据里包含了线程信息;java里在A线程里加了某个锁(包括普通锁和读写锁),那么一定要在该线程释放对应的锁(如普通锁,或者读写锁的读锁或写锁);(Go里没有这个要求,在A线程加锁,可以在B线程释放锁,而且Go的锁不是可重入的)

    5.加了多少次锁就要释放多少次锁,比如普通lock在一个代码块里lock了两次,那么就必须unlock两次,否则其他地方仍然是无法获得锁的;这个同样适用于读锁,比如rwLock加了3次读锁,这个时候写锁被阻塞,必须释放三次读锁写锁才会获得加锁的权限;

    6.rwLock加了写锁后,然后存在一个加写锁的被阻塞和加读锁的被阻塞的两个线程,此时释放rwLock的写锁,然后这两个阻塞的线程会公平的去“争抢”rwLock的写锁或读锁(而不是因为之前的是写锁,所以下一个一定是优先写锁或读锁)

    ,经过测试,到底是谁“争抢”成功,主要看这两个线程哪个先运行到rwLock加读/写锁的那句代码,先被阻塞的会先被唤醒去获得锁(当然不同的JVM可能不一样,所以这个不能当定论,只能说我的JVM测试结果是这样);

    7.读写锁在一般用于读次数远远大于写次数的情况,但是如果说长时间都是一直存在读线程加读锁,那么就会造成写饥饿,即写锁线程一直没法加写锁,这个没有好的解决方法,一般就是将锁的fair设置为true,不过这样锁的效率又会降低很多。

  • 相关阅读:
    37. VUE — webpack 基本使用
    36.VUE — 认识 Webpack 和 安装
    4. SpringBoot配置文件—YAML语法讲解
    3. IDEA 快速创建SpringBoot程序
    6. Maven 添加 镜像一些特性
    35. JS 模块化开发
    2. SPringBoot 解析HelloWorld 程序
    1. Maven 创建 SpringBoot项目 — HelloWorld — 我是踩了非常多的坑! 才写出来的 开学不顺 但是收获很多!!!
    34. VUE 的 编译作用域 以及 slot作用域插槽(获取组件作用域中的数据)
    【洛谷 3366】最小生成树_Kruskal
  • 原文地址:https://www.cnblogs.com/silentdoer/p/12745548.html
Copyright © 2020-2023  润新知