首先我们对读写锁做一个概述:

假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源。但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写,也就是说:读-读能共存,读-写不能共存,写-写不能共存。这就需要一个读/写锁来解决这个问题。

阿里巴巴四面最后的问题就涉及到了读写锁的实现。

问:对JAVA中的读写锁熟悉吗?

我:还可以...

问:简单介绍一下...

我:这是JAVA中的集合类,ReentrantReadWriteLock,分别处理读与写的操作,读读可以共存,读写不能共存,写写不能共存...

问:你自己实现一个读写锁

我:用synchronized,用一个队列...

问:不能那么麻烦,就用两个int值

我:两个int值,那一定是一个标记读次数,一个标记写次数啊,于是想了一会我想出了以下答案:

问:你这个可以是可以,但是如果读操作大量的话,写操作会产生饥饿等待...如何改进?

我想了想,是哦,然后脑子就短路了,挣扎,再挣扎...

我:给写加上优先级

问:不可以,就两个int

我:读次数设置一个阈值,超出主动释放

问:不可以,就两个int

我一脸懵逼...脑补画面

问:提醒你一下,lockwrite那里改一下

面试官发音不标准,我听了个lockread,想了半天,实在不知道怎么改,随便说了一个

问:我让你改lockwrite...

我:额,我看看...

又是漫长的等待...

我:没想出来...

问:把你那个条件拆开,让写占个坑...

我恍然大悟,我去...

然后他大概说了一遍,就草草结束了,郁闷中...

应该改成:

回来之后,大概看了一下,把整个程序写了一下:

  1. package com.darrenchan.lock;
  2.  
  3. /**
  4. * 用两个int变量实现读写锁
  5. * @author Think
  6. *
  7. */
  8. public class MyReadWriteLock {
  9.  
  10. private int readcount = 0;
  11. private int writecount = 0;
  12.  
  13. public void lockread() throws InterruptedException{
  14. while(writecount > 0){
  15. synchronized(this){
  16. wait();
  17. }
  18. }
  19. readcount++;
  20. //进行读取操作
  21. System.out.println("读操作");
  22. }
  23.  
  24. public void unlockread(){
  25. readcount--;
  26. synchronized(this){
  27. notifyAll();
  28. }
  29. }
  30.  
  31. public void lockwrite() throws InterruptedException{
  32. while(writecount > 0){
  33. synchronized(this){
  34. wait();
  35. }
  36. }
  37. //之所以在这里先++,是先占一个坑,避免读操作太多,从而产生写的饥饿等待
  38. writecount++;
  39. while(readcount > 0){
  40. synchronized(this){
  41. wait();
  42. }
  43. }
  44. //进行写入操作
  45. System.out.println("写操作");
  46. }
  47.  
  48. public void unlockwrite(){
  49. writecount--;
  50. synchronized(this){
  51. notifyAll();
  52. }
  53. }
  54.  
  55. public static void main(String[] args) throws InterruptedException {
  56. MyReadWriteLock readWriteLock = new MyReadWriteLock();
  57. for(int i = 0; i < 2; i++){
  58. Thread2 thread2 = new Thread2(i, readWriteLock);
  59. thread2.start();
  60. }
  61.  
  62. for (int i = 0; i < 10; i++) {
  63. Thread1 thread1 = new Thread1(i, readWriteLock);
  64. thread1.start();
  65. }
  66.  
  67. }
  68.  
  69. }
  70.  
  71. class Thread1 extends Thread{
  72. public int i;
  73. public MyReadWriteLock readWriteLock;
  74.  
  75. public Thread1(int i, MyReadWriteLock readWriteLock) {
  76. this.i = i;
  77. this.readWriteLock = readWriteLock;
  78. }
  79.  
  80. @Override
  81. public void run() {
  82. try {
  83. readWriteLock.lockread();
  84. Thread.sleep(1000);//模拟耗时
  85. System.out.println("第"+i+"个读任务");
  86. } catch (InterruptedException e) {
  87. e.printStackTrace();
  88. } finally {
  89. readWriteLock.unlockread();
  90. }
  91. }
  92. }
  93.  
  94. class Thread2 extends Thread{
  95. public int i;
  96. public MyReadWriteLock readWriteLock;
  97.  
  98. public Thread2(int i, MyReadWriteLock readWriteLock) {
  99. this.i = i;
  100. this.readWriteLock = readWriteLock;
  101. }
  102.  
  103. @Override
  104. public void run() {
  105. try {
  106. readWriteLock.lockwrite();
  107. Thread.sleep(1000);
  108. System.out.println("第"+i+"个写任务");
  109. } catch (InterruptedException e) {
  110. e.printStackTrace();
  111. } finally {
  112. readWriteLock.unlockwrite();
  113. }
  114. }
  115. }

执行结果:

写操作
第0个写任务
读操作
读操作
读操作
读操作
读操作
读操作
读操作
读操作
读操作
读操作
第9个读任务
第3个读任务
第1个读任务
第8个读任务
第2个读任务
第0个读任务
第7个读任务
第4个读任务
第5个读任务
第6个读任务
写操作
第1个写任务

当然这是简单的,还可以进一步加深,可以参考博客:http://ifeve.com/read-write-locks/#simple

注:以上代码在++和--的时候仍然会产生并发异常,建议用AtomicInteger类型,在硬件上保证++和--操作不会出现并发异常。

阿里巴巴面试之利用两个int值实现读写锁的更多相关文章

  1. 用两个int值实现读写锁

    private int readcount = 0; private int writecount = 0; public void lockread() throws InterruptedExce ...

  2. 两个int值相乘超过int最大值

    System.out.println(100000000*1000 ); //输出结果是:1215752192 先将100000000*1000 的结果转化为二进制: 10111 01001000 0 ...

  3. 并发系列5-大白话聊聊Java并发面试问题之微服务注册中心的读写锁优化【石杉的架构笔记】

  4. 问题:两个对象值相同(x.equals(y) == true),但是可能存在hashCode不同吗?

    面试官的考察点 这道题仍然是考察JVM层面的基本知识,面试官认为,基本功扎实,才能写出健壮性和稳定性很高的代码. 涉及到的技术知识 (x.equals(y)==true),这段代码,看起来非常简单,但 ...

  5. Flash图解线程池 | 阿里巴巴面试官希望问的线程池到底是什么?

    前言 前几天小强去阿里巴巴面试Java岗,止步于二面. 他和我诉苦自己被虐的多惨多惨,特别是深挖线程和线程池的时候,居然被问到不知道如何作答. 对于他的遭遇,结合他过了一面的那个嘚瑟样,我深表同情(加 ...

  6. 牛客网Java刷题知识点之Map的两种取值方式keySet和entrySet、HashMap 、Hashtable、TreeMap、LinkedHashMap、ConcurrentHashMap 、WeakHashMap

    不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...

  7. two pointers思想 ---- 利用两个i, j两个下标,同时对序列进行扫描,以O(n)复杂度解决问题的一种思想

    two pointers思想 ---- 利用两个i, j两个下标,同时对序列进行扫描,以O(n)复杂度解决问题的一种思想, 如果能用这种思想解决问题,那么会大大降低程序的复杂度. 两个利用这个思想的例 ...

  8. 阿里巴巴--java多线程的两种实现方式,以及二者的区别

    阿里巴巴面试的时候,昨天问了我java面试的时候实现java多线程的两种方式,以及二者的区别当时只回答了实现线程的两种方式,但是没有回答上二者的区别: java实现多线程有两种方式: 1.继承Thre ...

  9. 利用checkbox的到值,并且存到数据库修改的话要显示之前选择的

    在前台当然是利用checkbox来得到复选框的语言:{% for language in languages%}<input type="checkbox" name=&qu ...

随机推荐

  1. MongoDB--集群

    为什么需要集群 为了让数据安全 高(24* 7)数据可用性 灾难恢复 无停机维护(如备份,索引重建,压实) 读缩放(额外的副本读取) 副本集对应用程序是透明 设置集群 准备工作 在MongoDB的集群 ...

  2. Metasploit AFP爆破模块afp_login

    Metasploit AFP爆破模块afp_login   AFP是苹果系统支持的文件服务.用户可以使用指定的账户名和密码进行远程文件管理.afp_login是一个AFP认证信息暴力破解模块.它支持对 ...

  3. 关于H5在移动端架构的优化设计总结

    各大互联网公司采取的策略 一.百度移动前端首页 1. 对于首屏的静态文件css/js,在上线前全部编译直出到HTML文件中:整个首页的渲染只需要一次请求: 2.使用缓存:把不变的js/css/html ...

  4. POJ.3648.Wedding(2-SAT)

    题目链接 题意看这吧..https://www.cnblogs.com/wenruo/p/5885948.html \(Solution\) 每对夫妇只能有一个坐在新娘这一边,这正符合2-SAT初始状 ...

  5. 洛谷P1432 倒水问题(CODEVS.1226)

    To 洛谷.1432 倒水问题 题目背景 In the movie "Die Hard 3", Bruce Willis and Samuel L. Jackson were co ...

  6. PCB封装步骤教程

    疑问解答:为什么要封装? 就是元器件往PCB板上焊接时在板上的焊盘尺寸. 这里我以AT89C51单片机为例: 1.首先新建一个PCB元件库. 再找一个路径保存起来命名为DIP40,方便以后寻找 选择菜 ...

  7. json与xml数据输出类

    class Response { /** * 按json方式输出通信数据 * @param integer $code 状态码 * @param string $message 提示信息 * @par ...

  8. godaddy如何联系客服帮助的技巧和方法

    众所周知,Godaddy是世界最大的域名商和空间商,很多人喜欢在那里买域名或者空间,可是,当我们的域名空间出了问题要怎么办呢?今天闪电博客就给大家介绍一些Godaddy客服联系技巧,减少大家等待的时间 ...

  9. vim 语法着色完全配置

    原文地址:http://blog.sina.com.cn/s/blog_878940b3010156ku.html 在终端输入:sudo vim /etc/vim/vimrc   打开配置文件.编辑命 ...

  10. PKCS 15 个标准

    PKCS 全称是 Public-Key Cryptography Standards ,是由 RSA 实验室与其它安全系统开发商为促进公钥密码的发展而制订的一系列标准. 可以到官网上看看 What i ...