一道面试题比较synchronized和读写锁
一、科普定义
这篇博文的两个主角“synchronized”和“读写锁”
1)synchronized
这个同步关键字相信大家都用得比较多,在上一篇“多个线程之间共享数据的方式”中也详细列举他的应用,在这就不多说只做几点归纳:
- Java提供这个关键字,为防止资源冲突提供的内置支持。当任务执行到被synchronized保护的代码片段的时候,它检查锁是否可用,然后获取锁,执行代码,释放锁。
- 常用这个关键字可以修饰成员方法和代码块
2)读写锁
我们对数据的操作无非两种:“读”和“写”,试想一个这样的情景,当十个线程同时读取某个数据时,这个操作应不应该加同步。答案是没必要的。只有以下两种情况需要加同步:
- 这十个线程对这个公共数据既有读又有写
- 这十个线程对公共数据进行写操作
- 以上两点归结起来就一点就是有对数据进行改变的操作就需要同步
所以
- public synchronized Object getData(String key){
- Object result = map.get(key);
- if(result ==null){
- result = "new";//用这步代替访问数据库得数据
- }
- return result;
- }
- public synchronized Object getData(String key){
- Object result = map.get(key);
- if(result ==null){
- result = "new";//用这步代替访问数据库得数据
- }
- return result;
- }
用读写锁实现
- public Object getData(String key){
- rw.readLock().lock();//在读前先上读锁
- Object result = null;
- try{
- result = map.get(key);
- //这个if比较关键,它避免了多余的几次对数据哭的读取
- if(result==null){
- //如果内存中没有所要数据
- rw.readLock().unlock();
- rw.writeLock().lock();
- if(result==null){
- try{
- //我们用这个代替对数据库访问得到数据的步骤
- result = "new";
- }finally{
- rw.writeLock().unlock();
- }
- rw.readLock().lock();
- }
- }
- }finally{
- rw.readLock().unlock();
- }
- return result;
- }
- public Object getData(String key){
- rw.readLock().lock();//在读前先上读锁
- Object result = null;
- try{
- result = map.get(key);
- //这个if比较关键,它避免了多余的几次对数据哭的读取
- if(result==null){
- //如果内存中没有所要数据
- rw.readLock().unlock();
- rw.writeLock().lock();
- if(result==null){
- try{
- //我们用这个代替对数据库访问得到数据的步骤
- result = "new";
- }finally{
- rw.writeLock().unlock();
- }
- rw.readLock().lock();
- }
- }
- }finally{
- rw.readLock().unlock();
- }
- return result;
- }
代码分析:
- 用第一种方法处理,整个过程比较粗线条,代码比较简单单执行效率很低。这种方法的中心思想是不管你是什么操作,但凡涉及到公共资源就都给你同步。这么做可以是可以但是并不好。
- 第二种用读写锁处理显然是对前者的一个优化,对第二种方法做如下几点说明:
- 关于unlock操作,我们知道只要是上了锁就必须要解锁,但是有这么一种情况就是当你上完锁后在执行解锁操作前程序出现异常,那这个所可能就一直存在。所以针对这个问题我们一般将unlock操作放在finally代码块中,就可以保证上了的锁一定会被解。
- 上面的两次if判断,第一个if相信大家很好理解。但为什么要用第二个if呢?再假设一个场景,现在有十个线程来读这个数据,而这个数据又不存在与缓存区,那么这十个线程中最先到的线程将执行“rw.writeLock().lock();”而另外九个线程将被阻塞,当第一个线程读完以后缓存区实际上已经就有了这个数据,但另外九个阻塞在“rw.writeLock().lock();”如果不加这层if他们会继续访问数据库,由此可见加了这层if对整个过程影响很大。这是比较细节的一点,就这一点Java的API文档也考虑到了,它的样例代码如下:
- class CachedData {
- Object data;
- volatile boolean cacheValid;
- ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
- void processCachedData() {
- rwl.readLock().lock();
- <span style="color: rgb(255, 0, 0);">if (!cacheValid)</span> {
- // Must release read lock before acquiring write lock
- rwl.readLock().unlock();
- rwl.writeLock().lock();
- // Recheck state because another thread might have acquired
- // write lock and changed state before we did.
- <span style="color: rgb(255, 0, 0);"> if (!cacheValid)</span> {
- data = ...
- cacheValid = true;
- }
- // Downgrade by acquiring read lock before releasing write lock
- rwl.readLock().lock();
- rwl.writeLock().unlock(); // Unlock write, still hold read
- }
- use(data);
- rwl.readLock().unlock();
- }
- }
- class CachedData {
- Object data;
- volatile boolean cacheValid;
- ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
- void processCachedData() {
- rwl.readLock().lock();
- <span style="color:#ff00;">if (!cacheValid)</span> {
- // Must release read lock before acquiring write lock
- rwl.readLock().unlock();
- rwl.writeLock().lock();
- // Recheck state because another thread might have acquired
- // write lock and changed state before we did.
- <span style="color:#ff00;"> if (!cacheValid)</span> {
- data = ...
- cacheValid = true;
- }
- // Downgrade by acquiring read lock before releasing write lock
- rwl.readLock().lock();
- rwl.writeLock().unlock(); // Unlock write, still hold read
- }
- use(data);
- rwl.readLock().unlock();
- }
- }

学习在继续!!!Go!Go!Go!!!
一道面试题比较synchronized和读写锁的更多相关文章
- <转>一道面试题比较synchronized和读写锁
一.科普定义(原文:http://903497571.iteye.com/blog/1874752) 这篇博文的两个主角“synchronized”和“读写锁” 1)synchronized 这个同步 ...
- 比较synchronized和读写锁
一.科普定义 这篇博文的两个主角“synchronized”和“读写锁” 1)synchronized 这个同步关键字相信大家都用得比较多,在上一篇“多个线程之间共享数据的方式”中也详细列举他的应用, ...
- Java 线程锁机制 -Synchronized Lock 互斥锁 读写锁
(1)synchronized 是互斥锁: (2)ReentrantLock 顾名思义 :可重入锁 (3)ReadWriteLock :读写锁 读写锁特点: a)多个读者可以同时进行读b)写者必须互斥 ...
- 浅谈Java中的锁:Synchronized、重入锁、读写锁
Java开发必须要掌握的知识点就包括如何使用锁在多线程的环境下控制对资源的访问限制 ◆ Synchronized ◆ 首先我们来看一段简单的代码: 12345678910111213141516171 ...
- 201709020工作日记--synchronized、ReentrantLock、读写锁
1.reentrantLock java.util.concurrent.lock 中的Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java 类,而不是作为语言的特性来实现.这就为Lock ...
- 多线程面试题系列(14):读者写者问题继 读写锁SRWLock
在第十一篇文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题.问题虽然得到了解决,但代码有点复杂.本篇将介绍一种新方法--读写锁SRWLock来解决这一问题.读写锁在对资源进行保护的同时,还 ...
- 【分布式锁】07-Zookeeper实现分布式锁:Semaphore、读写锁实现原理
前言 前面已经讲解了Zookeeper可重入锁的实现原理,自己对分布式锁也有了更深的认知. 我在公众号中发了一个疑问,相比于Redis来说,Zookeeper的实现方式要更好一些,即便Redis作者实 ...
- java多线程-读写锁
Java5 在 java.util.concurrent 包中已经包含了读写锁.尽管如此,我们还是应该了解其实现背后的原理. 读/写锁的 Java 实现(Read / Write Lock Java ...
- 可重入锁 公平锁 读写锁、CLH队列、CLH队列锁、自旋锁、排队自旋锁、MCS锁、CLH锁
1.可重入锁 如果锁具备可重入性,则称作为可重入锁. ========================================== (转)可重入和不可重入 2011-10-04 21:38 这 ...
随机推荐
- 设计模式~简单工厂模式(Factory)
简单工厂模式Simple Factory根据提供给它的数据,返回一个类的实例.通常它返回的类都有一个公共的父类(或者接口对象). 简单工厂的作用是实例化对象,而不需要客户了解这个对象属于哪个具体的子类 ...
- LNMP 环境发布项目
发布地址 /srv/www/wx 默认mysql 外部访问权限关闭,需开启 另:注意数据库没有导入,index.php会是空白 chmod -R 777 /var var的权限就变成777,var下的 ...
- [ROS]3 Linux编程练习
一起做RGB-SLAM(2)实验 第二讲 从图像到点云 http://www.cnblogs.com/gaoxiang12/p/4652478.html exbot@ubuntu:~$ cd Code ...
- WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform
参看:http://www.secdoctor.com/html/yyjs/31101.html
- Collections的排序之一(Java)
package home.collection.arr; import java.util.ArrayList; import java.util.Collections; import java.u ...
- python 归档tarfile,zipfile学习
一.tarfile 用法: tarfile.open(cls, name=None, mode='r', fileobj=None, bufsize=10240, **kwargs) 返回一个Tar ...
- tcp/ip分片
from http://blog.csdn.net/cumirror/article/details/5071234 前段时间要做一个关于网络嗅探的程序,里面要重组IP分片,TCP分片. 但做的时候忽 ...
- Android初体验
上文提到使用genymotion来运行android项目,结果却是令人失望,我这边使用的是代理账户,尽管我在Setting中配置了代理,还是不能登录我注册的账户,郁闷,于是本文采用的是我自己的手机作为 ...
- vs2013 visual studio 插件安装
svn插件: AnkhSVN是一款在VS中管理Subversion的插件,您可以在VS中轻松的提交.更新.添加文件,而不用在命令行或资源管理器中提交.而且该插件属于开源项目· 官网:htt ...
- PostgreSQL trigger (function) examples
postgres=# \c warehouse_db You are now connected to database "warehouse_db" as user " ...