<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    和風細雨

    世上本無難事,心以為難,斯乃真難。茍不存一難之見于心,則運用之術自出。

    讀寫鎖的使用

    本文內容

    何時該使用讀寫鎖.
    讀寫鎖的寫法.
    理解讀寫鎖和線程互斥的區別。

    復習-同步化的概念

    當一個方法或代碼塊被聲明成synchronized,要執行此代碼必須先取得一個對象實例或this的鎖定,這個鎖定要在synchronized修飾的方法或代碼塊執行完后才能釋放掉(無論這段代碼是怎樣返回的,是正常運行還是異常運行)。每個對象只有一個鎖定,如果有兩個不同的線程試圖同時調用同一對象的同步方法,最終只會有一個能運行此方法,另外一個要等待第一個線程釋放掉鎖定后才能運行此方法。

    讀寫鎖應用的場合

    我們有時會遇到對同一個內存區域如數組或者鏈表進行多線程讀寫的情況,一般來說有以下幾種處理方式: 1.不加任何限制,多見于讀取寫入都很快的情況,但有時也會出現問題. 2.對讀寫函數都加以同步互斥,這下問題是沒了,但效率也下去了,比如說兩個讀取線程不是非要排隊進入不可. 3.使用讀寫鎖,安全和效率都得到了解決,特別合適讀線程多于寫線程的情況.也就是下面將要展現的模式.

    讀寫鎖的意圖

    讀寫鎖的本意是分別對讀寫狀態進行互斥區分,有互斥時才加鎖,否則放行.互斥的情況有: 1.讀寫互斥. 2.寫寫互斥. 不互斥的情況是:讀讀,這種情況不該加以限制. 程序就是要讓鎖對象知道當前讀寫狀態,再根據情況對讀寫的線程進行鎖定和解鎖。

    讀寫線程都要操作的數據類

    讀寫線程都要操作的數據是鏈表datas。
    注意其中try...finally 的寫法,它保證了加鎖解鎖過程是成對調用的

     

    lpublic class DataLib {
         private List<String> datas;
     
         private ReadWriteLock lock;
     
         public DataLib() {
             datas = new ArrayList<String>();
             lock = new ReadWriteLock();
         }
     
         // 寫入數據,這時不能讀取
         public void writeData(List<String> newDatas) {
             try {
                 lock.writeLock();
                 Test.sleep(2);
                 datas=newDatas;
             } finally {
                 lock.writeUnlock();
             }
         }
     
         // 讀取數據,這時不能寫入
         public List<String> readData() {
             try {
                 lock.readLock();
                 Test.sleep(1);            
                 return datas;
             } finally {
                 lock.readUnlock();
             }
     
         }
     
     }



     

    讀寫鎖ReadWriteLock類

    public class ReadWriteLock{
        // 讀狀態
        private boolean isRead;
       
        // 寫狀態
        private boolean isWrite;
       
        public synchronized void readLock(){
            // 有寫入時讀取線程停止
            while(isWrite){
                try{   
                    System.out.println("有線程在進行寫入,讀取線程停止,進入等待狀態");
                    wait();
                }
                catch(InterruptedException ex){
                    ex.printStackTrace();
                }
            }
           
            System.out.println("設定鎖為讀取狀態");
            isRead=true;
        }
       
        public synchronized void readUnlock(){
            System.out.println("解除讀取鎖");
            isRead=false;
            notifyAll();
        }

         public synchronized void writeLock(){
            // 有讀取時讀取線程停止
            while(isRead){
                try{   
                    System.out.println("有線程在進行讀取,寫入線程停止,進入等待狀態");
                    wait();
                }
                catch(InterruptedException ex){
                    ex.printStackTrace();
                }
            }
           
            // 有寫入時寫入線程也一樣要停止
            while(isWrite){
                try{   
                    System.out.println("有線程在進行寫入,寫入線程停止,進入等待狀態");
                    wait();
                }
                catch(InterruptedException ex){
                    ex.printStackTrace();
                }
            }
           
            System.out.println("設定鎖為寫入狀態");
            isWrite=true;
        }
       
        public synchronized void writeUnlock(){
            System.out.println("解除寫入鎖");
            isWrite=false;
            notifyAll();
        }
    }

    寫線程類Writer -它用于往DataLib類實例中的datas字段寫數據

    分析其中dataLib字段的用意。
    注意并記住其中持續調用及使用隨機數的方法。

     

    lpublic class Writer implements Runnable{
         private DataLib dataLib;
         private static final Random random=new Random();
         private String[] mockDatas={"","","","","","","","","",""};    
         
         public Writer(DataLib dataLib,String[] mockDatas){
             this.dataLib=dataLib;
             this.mockDatas=mockDatas;
             
             Thread thread=new Thread(this);
             thread.start();
         }
         
         public void run(){
             while(true){
                 Test.sleep(random.nextInt(3));
                 
                 int startIndex=random.nextInt(mockDatas.length);
                 
                 ArrayList<String> newDatas=new ArrayList<String>();
                 for(int i=startIndex;i<mockDatas.length;i++){
                     newDatas.add(mockDatas[i]);
                 }
                 
                 dataLib.writeData(newDatas);
             }
         }
     }

    讀線程類Reader  -它用于從DataLib類實例中的datas字段讀取數據

    分析其中dataLib字段的用意。
    注意并記住其中持續調用及使用隨機數的方法。

    public class Reader implements Runnable{
        private DataLib dataLib;
        private static final Random random=new Random();
       
        public Reader(DataLib dataLib){
            this.dataLib=dataLib;
       
            Thread thread=new Thread(this);
            thread.start();
        }
       
        public void run(){
            while(true){
                Test.sleep(random.nextInt(2));           
                List<String> datas=dataLib.readData();
               
                System.out.print(">>取得數組為:");
                for(String data:datas){
                    System.out.print(data+",");
                }
                System.out.print("\n");
            }
        }
    }

    將代碼運行起來

    右邊的代碼創建了兩個寫線程和三個讀線程,它們都是對dataLib實例進行操作的。
    五個線程都有一個dataLib字段,都提供了一個帶參構造函數以給datas字段賦值,這就保證了五個線程操作的都是一個實例的同一字段,也就是同一片內存。
    讀寫鎖就是對這五個線程進行控制的。
    當有一個讀線程在操作時,其它的寫線程無法進行操作,讀線程可以正常操作,互不干擾。
    當有一個寫線程在操作時,其它的讀線程無法進行操作。

     

     public class Test{
         public static void main(String[] args){
             DataLib dataLib=new DataLib();
             
             String[] mockDatas1={"","","","","","","","","",""};
             Writer writer1=new Writer(dataLib,mockDatas1);
             
             String[] mockDatas2={"","","","","","","","","","","",""};
             Writer writer2=new Writer(dataLib,mockDatas2);
             
             Reader reader1=new Reader(dataLib);
             Reader reader2=new Reader(dataLib);
             Reader reader3=new Reader(dataLib);
         }
         
         
         // 用于延時
         public static void sleep(int sleepSecond){
             try{
                 Thread.sleep(sleepSecond*1000);
             }
             catch(Exception ex){
                 ex.printStackTrace();
             }
         }
     }

    小結

    當多個線程試圖對同一內容進行讀寫操作時適合使用讀寫鎖。
    請理解并記住ReadWriteLock類讀寫鎖的寫法.
    讀寫鎖相對于線程互斥的優勢在于高效,它不會對兩個讀線程進行盲目的互斥處理,當讀線程數量多于寫線程尤其如此,當全是寫線程時兩者等效。

    posted on 2008-02-22 14:28 和風細雨 閱讀(2600) 評論(2)  編輯  收藏 所屬分類: 線程

    評論

    # re: 讀寫鎖的使用 2010-11-26 17:04 ydu

    相同線程會死鎖
    read.lock()
    write.lock()
    write.unlock();
    read.unload();  回復  更多評論   

    # .[未登錄] 2014-11-12 15:08 .

    .  回復  更多評論   

    主站蜘蛛池模板: 国产精品内射视频免费| 天堂在线免费观看| 亚洲欧洲免费无码| 亚洲婷婷天堂在线综合| 91久久青青草原线免费| 亚洲免费视频播放| 无码日韩人妻av一区免费| 亚洲理论片在线观看| 日日麻批免费40分钟日本的| 亚洲成年人免费网站| 成全高清视频免费观看| 狠狠综合亚洲综合亚洲色| 国产在线a不卡免费视频| 黄色网址大全免费| 亚洲中文字幕无码一久久区| 女人隐私秘视频黄www免费| 亚洲精品午夜视频| 国产精品久免费的黄网站| 一级特级aaaa毛片免费观看| 久久亚洲国产欧洲精品一| 最近免费中文字幕大全高清大全1| 亚洲另类春色校园小说| 国产精品久免费的黄网站| 久久久久久久国产免费看| 亚洲色av性色在线观无码| 日韩成人免费aa在线看| 国产黄在线播放免费观看| 亚洲熟妇无码爱v在线观看| 国产在线观看免费不卡| 好紧我太爽了视频免费国产| 亚洲国产人成在线观看| 亚洲一区无码精品色| 在线观看www日本免费网站| 国产成人亚洲精品蜜芽影院| 亚洲熟妇无码乱子AV电影| 91在线视频免费91| CAOPORN国产精品免费视频| 亚洲第一香蕉视频| 亚洲国产精品视频| 日韩在线播放全免费| 一级毛片aa高清免费观看|