阿里巴巴面試之利用兩個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類型,在硬件上保證++和--操作不會出現並發異常。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM