關於讀寫鎖算法的java實現及思考 – JAVA編程語言程序開發技術文章

 問題背景:多個線程對一個共享的資源進行讀寫訪問。寫線程之間需要互斥,讀線程跟寫線程需要互斥,讀線程之間不用互斥。
  早些時候聽張sir的課,講述java5中增強並發的功能。用java.util.concurrent.locks中ReadWriteLock 可以輕松解決讀寫鎖問題。我在思考如果沒有ReadWriteLock,單靠synchronized可以怎樣做呢? 的確,比較麻煩。
  1.結合張sir傳授的面向對象的設計思想,首先設計一個業務類Business作為共享資源,封裝write跟read方法。
  2.因為write必定互斥,所以直接定義synchronized
  3.read之間不要互斥 所以read 不能直接定義synchronized的 但是 write跟read 需要互斥 如何控制 我想到的一個方法是在read裡 加入synchronized(this){} 同時定義readThreads計數器作為信號量 我試想下會出現下面幾種情況:
  read[m]表示某個線程的read方法
  write[n] 同上
  1>read[m]中執行到synchronized(this){readThreads++;}時 write[n]來瞭 write[n] 會被自身的synchronized阻塞
  2>read[m]在do something(此時無鎖)時 write[n] 來瞭 因為 readThreads!=0 而被迫wait
  3> 每次read[m]結束時 wait中的write[n]會被notify 但如果發現還有其他的read的話 write[n] 隻能無奈地再次wait
  4>當readThreads==0並且調用notifyAll 時 read[m] 和 write[n] 會競爭cpu 如果write[n]再次落敗,則會出現1>或3> ; 如果成瞭,則如下:
  5> 如果write[n] wait中醒來占鎖,read[m]被阻塞synchronized(this){readThreads++;}之上
  6>如果被阻塞的write[n]占鎖,read[m]被阻塞synchronized(this){readThreads++;}之上
  從以上看來read 和 write 是互斥的
  4.實現細節如下:<如有錯誤歡迎指出交流>
package communication;
import java.util.Random;

public class ReadWriteLockTest {
        public static void main(String[] args){
                final Business business = new Business();
               
                //啟動4線程 2讀 2寫
                for(int i=1;i<=2;i++){
                                new Thread(new Runnable(){
                                        public void run() {
                                                for(int j=1;j<1000;j++){
                                                        business.read();
                                                        try {
                                                                Thread.sleep(900);
                                                        } catch (InterruptedException e) {
                                                                e.printStackTrace();
                                                        }                                                       
                                                }                                       
                                        }                               
                                }).start();
                               
                                new Thread(new Runnable(){
                                        public void run() {
                                                Random r = new Random();
                                                for(int j=1;j<1000;j++){
                                                        int i = r.nextInt(100);
                                                        business.write(i);
                                                        try {
                                                                Thread.sleep(1000);
                                                        } catch (InterruptedException e) {
                                                                e.printStackTrace();
                                                        }
                                                }                                       
                                        }               
                                }).start();
                }
               
        }
       
}
//封裝的業務類
class Business{
        private int data=0; //共享資源屬性
        private int readThreads = 0; //讀線程數
        //private boolean isWriting  = false;
        //是否執行寫 後來發現不需要 當write搶占鎖時 所有的read 都被擋在synchronized (this){}之上 無機會執行wait
        public void read(){
                synchronized (this) {       
                        /*while(isWriting){
                                try {                       
                                        this.wait();                                       
                                } catch (InterruptedException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                }
                        }*/
                        //readThreads不被鎖的話 會出現read和write不互斥的小概率事件 導致線程不安全
                        readThreads++;
                       
                }
               
                System.out.println(Thread.currentThread().getName()+" read begin");
                System.out.println(Thread.currentThread().getName()+" read:"+data);
                System.out.println(Thread.currentThread().getName()+" read finish");
                       
                synchronized (this) {
                        readThreads–;
                        this.notifyAll();
                }       
        }
       
        public synchronized void write(int i){
                while(readThreads != 0){//當read 正處於do something狀態時 來個write 那就隻有等等先瞭
                        try {
                                this.wait();
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                }
                //isWriting = true;
                System.out.println(Thread.currentThread().getName()+" write start");
                data = i;
                System.out.println(Thread.currentThread().getName()+" write:"+i);
                System.out.println(Thread.currentThread().getName()+" write over");
                //isWriting = false;
                this.notifyAll();
        }
}

  思考中:
  5.當讀頻繁時 readThreads會長時間!= 0 寫線程會餓死 這個可以如何解決?

 

摘自  Goodspeed85
 

發佈留言