读为什么要加锁?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

读锁有什么用?读为什么要加锁?相关推荐

  1. mysql replication 读锁_MySQL介于普通读和加锁读之间的读取方式:semi-consi

    推荐阅读: 事前准备 为了故事的顺利发展,我们先建一个表,并向表中插入一些记录,下边是SQL语句: CREATE TABLE hero ( number INT, name VARCHAR(100), ...

  2. Mysql加锁过程详解(3)-关于mysql 幻读理解

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  3. Mysql加锁过程详解(2)-关于mysql 幻读理解

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  4. 图文深入解析 JAVA 读写锁,为什么读锁套写锁会死锁,反过来却不会?

    一.回顾基本的读写锁 我们知道读写锁 #java.util.concurrent.locks.ReentrantReadWriteLock 是一个 "读写互斥,写写互斥,读读共享" ...

  5. 一条简单的更新语句,MySQL是如何加锁的?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:Java_老男孩 来源:https://urlify.cn/ ...

  6. InnoDB解决幻读的方案--LBCCMVCC

    最近要在公司内做一次技术分享,思来想去不知道该分享些什么,最后在朋友的提示下,准备分享一下MySQL的InnoDB引擎下的事务幻读问题与解决方案--LBCC&MVCC.经过好几天的熬夜通宵,终 ...

  7. 一文读懂MySQL事务锁、事务级别

    锁 性能分:乐观(比如使用version字段比对,无需等待).悲观(需要等待其他事务) 乐观锁,如它的名字那样,总是认为别人不会去修改,只有在提交更新的时候去检查数据的状态.通常是给数据增加一个字段来 ...

  8. mysql主键更新被锁_MySQL 的加锁处理,你都了解的一清二楚了吗?

    MySQL加锁分析,一直是一个比较困难的话题. 我在工作过程中,经常会有同事咨询这方面的问题.本文,准备就MySQL加锁问题,展开较为深入的分析与讨论,主要是介绍一种思路,运用此思路,拿到任何一条SQ ...

  9. MqSql的加锁分析

    2019独角兽企业重金招聘Python工程师标准>>> (1)MVCC与基于锁的并发控制 MySql的InnoDB引擎,实现的是基于多版本的并发控制协议:MVCC. MVCC最大的好 ...

最新文章

  1. MFC中MessageBox()用法
  2. Mac python3.x使用HTMLTestRunner.py生成html格式的测试报告
  3. 伤疤好了有黑印怎么办_春藤家长圈|家有二孩,老大老二一起抢东西,家长该怎么办?...
  4. Scala 入门2(数组、List、Set、Map、元组、Option、Iterator)
  5. php多个表中查找数据_Excel实战技巧74: 在工作表中创建搜索框来查找数据
  6. 全局唯一递增的id_生成全局唯一id的几种方式
  7. python爬虫03
  8. 《R语言数据分析与挖掘实战》——3.2 数据特征分析
  9. 【数字信号去噪】基于matlab同心兰姆波模式分解【含Matlab源码 679期】
  10. linux设置ipsan_linux 配置SAN存储-IPSAN
  11. 弹性均质圆环法计算过程_均质圆环胎刚体的转动惯量
  12. lol无法连接服务器win10系统,win10系统中lol无法连接服务器怎么办
  13. macmini性能测试软件,Mac mini
  14. [生命科学] snapgene 构建载体方法分享
  15. BigDecimal比较大小工具类
  16. python调用百度地图API 实现单点沿线轨迹运动
  17. 2021-2027全球与中国工业自动化定位传感器市场现状及未来发展趋势
  18. 若依专题 线程池配置
  19. Fusion 360 常见问题
  20. 无法写入最后一个_影驰擎 GA-E 16TB SSD评测:3.96TB持续稳定写入,你想要的大容量来了...

热门文章

  1. default默认值 unique单列唯一和联合唯一 primary key主键 auto_increment自增 外键foregin key 表与表之间关系
  2. Android之蚂蚁森林能量水滴效果
  3. html网页鼠标样式、css精灵、iconfont、过渡动画笔记
  4. 猜字母 把abcd...s共19个字母组成的序列重复拼接106次,得到长度为2014的串。
  5. java lru_LRU的理解与Java实现
  6. android卸载保留数据,android在卸载应用程序后保留数据库
  7. 自动化工具Pyautogui和Pywinauto详细介绍和使用
  8. C语言零基础入门(一 简介)
  9. 网络安全应急响应----7、数据泄漏应急响应
  10. 5 Processes 上