zoukankan      html  css  js  c++  java
  • 阿里巴巴面试之利用两个int值实现读写锁

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

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

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

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

    我:还可以...

    问:简单介绍一下...

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

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

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

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

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

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

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

    我:给写加上优先级

    问:不可以,就两个int

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

    问:不可以,就两个int

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

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

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

    问:我让你改lockwrite...

    我:额,我看看...

    又是漫长的等待...

    我:没想出来...

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

    我恍然大悟,我去...

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

    应该改成:

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

    package com.darrenchan.lock;
    
    /**
     * 用两个int变量实现读写锁
     * @author Think
     *
     */
    public class MyReadWriteLock {
        
        private int readcount = 0;
        private int writecount = 0;
        
        public void lockread() throws InterruptedException{
            while(writecount > 0){
                synchronized(this){
                    wait();
                }
            }
            readcount++;
            //进行读取操作
            System.out.println("读操作");
        }
        
        public void unlockread(){
            readcount--;
            synchronized(this){
                notifyAll();
            }
        }
        
        public void lockwrite() throws InterruptedException{
            while(writecount > 0){
                synchronized(this){
                    wait();
                }
            }
            //之所以在这里先++,是先占一个坑,避免读操作太多,从而产生写的饥饿等待
            writecount++;
            while(readcount > 0){
                synchronized(this){
                    wait();
                }
            }
            //进行写入操作
            System.out.println("写操作");
        }
        
        public void unlockwrite(){
            writecount--;
            synchronized(this){
                notifyAll();
            }
        }
        
        public static void main(String[] args) throws InterruptedException {
            MyReadWriteLock readWriteLock = new MyReadWriteLock();
            for(int i = 0; i < 2; i++){
                Thread2 thread2 = new Thread2(i, readWriteLock);
                thread2.start();
            }
            
            for (int i = 0; i < 10; i++) {
                Thread1 thread1 = new Thread1(i, readWriteLock);
                thread1.start();
            }
            
        }
    
    }
    
    class Thread1 extends Thread{
        public int i;
        public MyReadWriteLock readWriteLock;
        
        public Thread1(int i, MyReadWriteLock readWriteLock) {
            this.i = i;
            this.readWriteLock = readWriteLock;
        }
    
        @Override
        public void run() {
            try {
                readWriteLock.lockread();
                Thread.sleep(1000);//模拟耗时
                System.out.println("第"+i+"个读任务");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                readWriteLock.unlockread();
            }
        }
    }
    
    
    class Thread2 extends Thread{
        public int i;
        public MyReadWriteLock readWriteLock;
        
        public Thread2(int i, MyReadWriteLock readWriteLock) {
            this.i = i;
            this.readWriteLock = readWriteLock;
        }
    
        @Override
        public void run() {
            try {
                readWriteLock.lockwrite();
                Thread.sleep(1000);
                System.out.println("第"+i+"个写任务");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                readWriteLock.unlockwrite();
            }
        }
    }

    执行结果:

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

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

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

  • 相关阅读:
    js穿梭框;将两个table中的数据选中移动
    MySQL权限管理实战
    CentOS 7平台rpm包部署MySQL 8.0、Spring Security权限注解
    Nginx服务器配置服务实战
    创建索引,这些知识应该了解
    如何实现对ELK各组件的监控?试试Metricbeat
    大数据量查询容易OOM?试试MySQL流式查询
    免费正版IntelliJ IDEA license详细指南
    MySQL查询语句进阶知识集锦
    ClickHouse性能优化?试试物化视图
  • 原文地址:https://www.cnblogs.com/DarrenChan/p/8619476.html
Copyright © 2011-2022 走看看