读锁有什么用?读为什么要加锁?
读为什么要加锁?ReadWriteLock为什么要有读锁?
1、有些同学认为读锁没有用,他们的理由是:读操作又不会修改数据,想读就读呗,无论读的是什么值,反正能读到。
2、也有同学认为读锁是为了防止多线程读到的数据不一致。
我认为不是这个原因,只需要问两个问题就知道了,首先问不一致的是什么?然后反问不一致会导致什么问题呢?
有些同学认为不一致就是有些线程读的是旧值,有些读的是新值,所以不一致。但是反问导致什么问题,就不是很好回答了,可能回答说为了保险吧,哈哈哈。
实际上即使加读锁,还是会存在有的线程读旧值,有的线程读新值,甚至非公平锁情况下,先开始的线程反而读到新值,而后开始的线程反而读到旧值,所以读锁并不是为了保证多线程读到的值是一样的。
3、那么读锁的作用是什么呢?
任何锁表面上是互斥,但本质是都是为了避免原子性问题(如果程序没有原子性问题,那只用volatile来避免可见性和有序性问题就可以了,效率更高),读锁自然也是为了避免原子性问题,比如一个long型参数的写操作并不是原子性的,如果允许同时读和写,那读到的数很可能是就是写操作的中间状态,比如刚写完前32位的中间状态。long型数都如此,而实际上一般读的都是复杂的对象,那中间状态的情况就更多了。
所以读锁是防止读到写的中间值。
测试不加读锁
public class Demo {public static final int MAX_VALUE = 2;//值,且值不大于 MAX_VALUElong value;//返回值long get(){CommonMethod.sleep(10);return value;}//值加1,模拟非原子的写操作void add(){//加法结果类似写操作的中间状态value++;CommonMethod.sleep(10);//重置为0if (value > MAX_VALUE){value = 0;}}public static void main(String[] args) {TestMethod.test(new Demo());}
}
公共代码:
public class CommonMethod {private static AtomicLong UNIQ_ID = new AtomicLong();public static void sleep(long time){try {TimeUnit.MILLISECONDS.sleep(time);} catch (InterruptedException e) {e.printStackTrace();}}public static void log(String log){System.out.println(new SimpleDateFormat("yyyyMMdd HH:mm:ss.SSS").format(new Date())+ " "+ Thread.currentThread().getName() + " " + log);}public static void start(Collection<Thread> threads){threads.forEach(t->t.start());}public static void join(Thread thread){try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}}public static void join(Collection<Thread> threads){threads.forEach(t-> join(t));}public static int randomInt(int high){return new Random().nextInt(high);}public static Long getUniqId(){return UNIQ_ID.getAndIncrement();}
}
测试程序如下:
public class TestMethod {public static void test(Demo demo) {long start = System.currentTimeMillis();List<Thread> threads = new LinkedList<>();for (int i=0;i<10000;i++){//读线程threads.add(new Thread(() -> {long value = demo.get();if (value > Demo.MAX_VALUE){CommonMethod.log("读到错误的数据了");System.exit(-1);}CommonMethod.log("get " + value);}, "thread-get-" + i));//写线程threads.add(new Thread(() -> demo.add() ,"thread-add-" + i));}CommonMethod.start(threads);CommonMethod.join(threads);CommonMethod.log(""+ demo.get());CommonMethod.log("耗时:"+(System.currentTimeMillis()-start));}
}
测试结果如下图:
使用读写锁
/*** 读写锁示例*/
public class ReadWriteLockDemo extends Demo {private final ReadWriteLock rw = new ReentrantReadWriteLock();private final Lock rl = rw.readLock();private final Lock wl = rw.writeLock();@Overridepublic long get(){rl.lock();try{return super.get();}finally {rl.unlock();}}@Overridepublic void add(){wl.lock();try{super.add();}finally{wl.unlock();}}public static void main(String[] args) {TestMethod.test(new ReadWriteLockDemo());}}
测试结果:
测试环境:4核 8G
读锁有什么用?读为什么要加锁?相关推荐
- mysql replication 读锁_MySQL介于普通读和加锁读之间的读取方式:semi-consi
推荐阅读: 事前准备 为了故事的顺利发展,我们先建一个表,并向表中插入一些记录,下边是SQL语句: CREATE TABLE hero ( number INT, name VARCHAR(100), ...
- Mysql加锁过程详解(3)-关于mysql 幻读理解
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- Mysql加锁过程详解(2)-关于mysql 幻读理解
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- 图文深入解析 JAVA 读写锁,为什么读锁套写锁会死锁,反过来却不会?
一.回顾基本的读写锁 我们知道读写锁 #java.util.concurrent.locks.ReentrantReadWriteLock 是一个 "读写互斥,写写互斥,读读共享" ...
- 一条简单的更新语句,MySQL是如何加锁的?
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:Java_老男孩 来源:https://urlify.cn/ ...
- InnoDB解决幻读的方案--LBCCMVCC
最近要在公司内做一次技术分享,思来想去不知道该分享些什么,最后在朋友的提示下,准备分享一下MySQL的InnoDB引擎下的事务幻读问题与解决方案--LBCC&MVCC.经过好几天的熬夜通宵,终 ...
- 一文读懂MySQL事务锁、事务级别
锁 性能分:乐观(比如使用version字段比对,无需等待).悲观(需要等待其他事务) 乐观锁,如它的名字那样,总是认为别人不会去修改,只有在提交更新的时候去检查数据的状态.通常是给数据增加一个字段来 ...
- mysql主键更新被锁_MySQL 的加锁处理,你都了解的一清二楚了吗?
MySQL加锁分析,一直是一个比较困难的话题. 我在工作过程中,经常会有同事咨询这方面的问题.本文,准备就MySQL加锁问题,展开较为深入的分析与讨论,主要是介绍一种思路,运用此思路,拿到任何一条SQ ...
- MqSql的加锁分析
2019独角兽企业重金招聘Python工程师标准>>> (1)MVCC与基于锁的并发控制 MySql的InnoDB引擎,实现的是基于多版本的并发控制协议:MVCC. MVCC最大的好 ...
最新文章
- MFC中MessageBox()用法
- Mac python3.x使用HTMLTestRunner.py生成html格式的测试报告
- 伤疤好了有黑印怎么办_春藤家长圈|家有二孩,老大老二一起抢东西,家长该怎么办?...
- Scala 入门2(数组、List、Set、Map、元组、Option、Iterator)
- php多个表中查找数据_Excel实战技巧74: 在工作表中创建搜索框来查找数据
- 全局唯一递增的id_生成全局唯一id的几种方式
- python爬虫03
- 《R语言数据分析与挖掘实战》——3.2 数据特征分析
- 【数字信号去噪】基于matlab同心兰姆波模式分解【含Matlab源码 679期】
- linux设置ipsan_linux 配置SAN存储-IPSAN
- 弹性均质圆环法计算过程_均质圆环胎刚体的转动惯量
- lol无法连接服务器win10系统,win10系统中lol无法连接服务器怎么办
- macmini性能测试软件,Mac mini
- [生命科学] snapgene 构建载体方法分享
- BigDecimal比较大小工具类
- python调用百度地图API 实现单点沿线轨迹运动
- 2021-2027全球与中国工业自动化定位传感器市场现状及未来发展趋势
- 若依专题 线程池配置
- Fusion 360 常见问题
- 无法写入最后一个_影驰擎 GA-E 16TB SSD评测:3.96TB持续稳定写入,你想要的大容量来了...
热门文章
- default默认值 unique单列唯一和联合唯一 primary key主键 auto_increment自增 外键foregin key 表与表之间关系
- Android之蚂蚁森林能量水滴效果
- html网页鼠标样式、css精灵、iconfont、过渡动画笔记
- 猜字母 把abcd...s共19个字母组成的序列重复拼接106次,得到长度为2014的串。
- java lru_LRU的理解与Java实现
- android卸载保留数据,android在卸载应用程序后保留数据库
- 自动化工具Pyautogui和Pywinauto详细介绍和使用
- C语言零基础入门(一 简介)
- 网络安全应急响应----7、数据泄漏应急响应
- 5 Processes 上