应用方案
前几天,一个做防复制检查的伙伴问了我一个问题。
---
多线程有一个变量,您需要读取它以确定是否写入信息。
我打算上锁,但是如果在读入时输入readlock,在写入时输入writelock的话,
这样做的话,读写有可能不同步。 但是,如果一起加入lock,就会产生与synchronized相同的效果,效率会降低
---
其实他的问题是以下场景:
高并发读/写请求
读取请求明显大于写入请求
在同步模式下同步锁定会导致性能下降。 本来,读取可以通过多线程同步进行,但同步锁定只能一次排队读取。
读取时添加readlock,写入时添加writelock,可以提高效率。 因为读取可以多线程同时执行。 但是,在线程a完成读取并被锁定的毫秒级时间,线程b也可能完成读取并在线程a之前修改了变量,这可能导致程序错误。
处理方案
我研究了读写锁,发现其实java已经正式给出了答案。 使用读/写锁定标志位解决读/写异步。
这就是先普及读写锁。
簧片锁:
读锁定拒绝其他线程获得写锁定,而读锁定不拒绝其他线程获得读锁定。 即使处于读锁定状态的多个线程同时被读取,也不会被阻止。
当多个读锁定同时工作时,其他要进行写锁定的线程将处于等待状态,并且在释放最后一个读锁定后才能进行锁定。
写锁定:
写锁定拒绝其他线程获取读锁定和写锁定。
在一个线程获取写锁定后,尝试获取写锁定的其他线程在释放写锁定之前无法解锁。
##代码示例
直接解读了Java官方样本。
class cached数据{
对象数据;
volatile boolean cacheValid;
finalreentreadwritelockrwl=newreentrantreadwritelock (;
void processCachedData (
rwl.readLock ().lock ); //1 .上簧片锁
if (! 验证缓存值(//2.缓存值
//mustreleasereadlockbeforeacquiringwritelock
rwl.readLock ().unlock ); //3 .解除簧片锁定
rwl.writeLock ().lock ); //4 .写锁定
try {
//recheckstatebecauseanotherthreadmighthave
//acquiredwritelockandchangedstatebeforewedid。
if (! 验证缓存值(//5.缓存值
数据=.
cacheValid=true;
}
//downgradebyacquiringreadlockbeforereleasingwritelock
rwl.readLock ().lock ); //6 .上簧片锁
} finally {
rwl.writeLock ().unlock ); //Unlock write,still hold read //7.解除写入锁定
}
}
try {
USE(data;
} finally {
rwl.readLock ().unlock ); //8 .解除簧片锁定
}
}
}
例如,当前有5个线程ABCDE,使用processCachedData ()方法可以了解以下步骤:
- DE线程延迟,ABC同时进入步骤1 .读锁定
- ABC进入步骤cacheValid的验证。 (在新实例中,cacheValid初始为fasle,因此进入if条件语句。)
- ABC按步骤3 .解除读锁定。
-此时,假设a先完成了步骤4 .写入锁定。
- BC无法获取写锁定,正在等待,并且在步骤4中被阻止。 加写锁定。 此时,d线程将使用processCachedData ()方法执行,并在步骤1 .中阻止读锁定。
- A进入步骤cacheValid的验证。
步骤5很重要,如果线程a完成写入,然后释放写锁定,则当新线程e获得写锁定时,将写入新数据。 在这种情况下,将出现程序错误,而不是同步锁定。
- A修改数据并将cacheValid设置为true。 步骤6和步骤7是写锁定降级操作。 也就是说,在写锁被释放时,首先降级为读锁。 这将使其他正在等待获取写锁定的线程在释放写锁定以确保同步之前继续等待。
- A执行步骤8将终止BC块,并由一个人获取写锁定。
如果你在学习Java或者工作中有任何问题都可以小组提问,阿里Java高级jjdlh可以直接讲解知识点,分享知识,整理和总结多年的工作经验,带大家全面、科学地建立自己的技术体系和技术认知! 请添加组并链接到课程。 是没有免费开发经验的误入歧途哦。 别乐意进去! 学习交流QQ群: 478052716