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


    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,不过这样锁的效率又会降低很多。

  • 相关阅读:
    获取Enum枚举值描述的几法方法
    Android开发入门 Button事件实现的方法(原创)
    最有价值的.Net第三方控件
    Eclipse快捷键大全(转载)
    recovery教程
    XP系统通过无线网卡共享宽带给其他设备,正确的共享设置(修正版,绝对可行)
    使用Eclipse写QT
    Android 4.0模拟器弹出“谷歌拼音输入法”已停止运行的解决方法
    C# 枚举用法总结
    谷歌安卓系统使用必读,什么是root, Recovery, Radio, APP TO SD, Rom
  • 原文地址:https://www.cnblogs.com/silentdoer/p/12745548.html
Copyright © 2020-2023  润新知