java中讀寫鎖ReadWriteLock

1.排他鎖(互斥鎖)的概念:java

       synchronized,ReentrantLock這些鎖都是排他鎖,這些鎖同一時刻只容許一個線程進行訪問。緩存

2.讀寫鎖的概念:dom

       分爲讀鎖和寫鎖,多個讀鎖不互斥,讀鎖和寫鎖互斥,寫鎖與寫鎖互斥。性能

3.讀寫鎖的好處:this

爲了提升性能,Java提供了讀寫鎖,在讀的地方使用讀鎖,在寫的地方使用寫鎖,靈活控制,若是沒有寫鎖的狀況下,讀是無阻塞的,在必定程度上提升了程序的執行效率。.net

       原來使用的互斥鎖只能同時間有一個線程在運行,如今的讀寫鎖同一時刻能夠多個讀鎖同時運行,這樣的效率比原來的排他鎖(互斥鎖)效率高。線程

       

4.讀寫鎖的原理分析:code

    Java中讀寫鎖有個接口java.util.concurrent.locks.ReadWriteLock,也有具體的實現ReentrantReadWriteLock,接口

     lock方法 是基於CAS 來實現的進程

   

public interface ReadWriteLock {  
    /** 
     * Returns the lock used for reading. 
     * 
     * @return the lock used for reading. 
     */  
    Lock readLock();  
  
    /** 
     * Returns the lock used for writing. 
     * 
     * @return the lock used for writing. 
     */  
    Lock writeLock();  
}

5.案例一:

package WriteReadLock;  
  
import java.util.Random;  
import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReadWriteLock;  
import java.util.concurrent.locks.ReentrantReadWriteLock;  
  
public class ReadWriterLockTest {  
    public static void main(String[] args) {  
        final Queue q3 = new Queue();  
        for(int i=0;i<3;i++)  
        {  
            new Thread(){  
                public void run(){  
                    while(true){  
                        q3.get();                         
                    }  
                }  
                  
            }.start();  
        }  
        for(int i=0;i<3;i++)  
        {         
            new Thread(){  
                public void run(){  
                    while(true){  
                        q3.put(new Random().nextInt(10000));  
                    }  
                }             
                  
            }.start();  
   }  
    }  
}  
  
  
class Queue{  
    //共享數據,只能有一個線程能寫該數據,但能夠有多個線程同時讀該數據。  
    private Object data = null;  
    //獲得讀寫鎖  
    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();  
      
    /** 
     * 將用於讀的get()和寫的put()放在同一個類中這樣是爲了對同一個資源data進行操做,造成互斥 
     */  
      
    /** 
     * 進行讀操做 
     * 能夠多個讀線程同時進入,寫線程不能執行 
     */  
    public void get(){  
        //獲取讀鎖,並加鎖  
        Lock readLock = readWriteLock.readLock();  
        readLock.lock();  
        try {  
            System.out.println(Thread.currentThread().getName() + " be ready to read data!");  
            Thread.sleep((long)(Math.random()*1000));  
            System.out.println(Thread.currentThread().getName() + "have read data :"+ data);          
              
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }finally {  
            //!!!!!!注意:鎖的釋放必定要在trycatch的finally中,由於若是前面程序出現異常,鎖就不能釋放了  
            //釋放讀鎖  
            readLock.unlock();  
        }  
  
          
    }  
      
    /** 
     * 進行寫操做 
     * 只能一個寫線程進入,讀線程不能執行 
     */  
    public void put(Object data){  
        //獲取寫鎖,並加鎖  
        Lock writeLock = readWriteLock.writeLock();  
        writeLock.lock();  
        try {  
            System.out.println(Thread.currentThread().getName() + " be ready to write data!");                    
            Thread.sleep((long)(Math.random()*1000));  
            this.data = data;         
            System.out.println(Thread.currentThread().getName() + " have write data: " + data);   
              
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }finally {  
            //釋放寫鎖  
            writeLock.unlock();  
        }  
          
    }  
}

沒有使用鎖以前:讀和寫交叉在一塊兒

 

在加入讀寫鎖以後:讀的過程當中,不會有寫

6.案例二:

package WriteReadLock;  
  
import java.util.HashMap;  
import java.util.Map;  
import java.util.Random;  
import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReadWriteLock;  
import java.util.concurrent.locks.ReentrantReadWriteLock;  
  
public class CacheDemo {  
    //用map來模擬緩存  
    Map<String,Object> cache = new HashMap<String,Object>();  
    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();  
  
      
    public static void main(String[] args) {  
        final CacheDemo cacheDemo = new CacheDemo();  
        for(int i=0;i<6;i++)  
        {  
            new Thread(){  
                public void run(){  
                    while(true){  
                      
                        System.out.println( cacheDemo.getData("key1").toString());  
                    }  
                }  
                  
            }.start();  
        }  
          
    }  
      
      
    Lock readLock = readWriteLock.readLock();  
    Lock writeLock = readWriteLock.writeLock();  
    //這裏必需要用volatie當一個寫線程設置value="aaaabbbb",必定要讓其餘的線程知道vlue的變化,這樣就不會被重複寫  
    volatile Object value;  
    public Object getData(String key){  
          
        readLock.lock();  
          
        try {  
            Thread.sleep(300);  
            System.out.println(" read");  
             value = cache.get(key);  
            if (value == null) {  
                  
                //這裏已經加了讀鎖,讀鎖中寫是不能容許的,因此要把這個鎖釋放掉  
                readLock.unlock();  
                writeLock.lock();  
                //防止,當多個寫者進程在等待,前面的寫進程已經賦值了,value已經不爲空了後面的等着的寫進程仍然繼續賦值  
                if(value == null){  
                    System.out.println("find null");  
                    
                    value="aaaabbbb";  
                    cache.put(key, value);  
                    System.out.println("write");  
                }  
                  
                  
                writeLock.unlock();  
                //重新加上讀鎖  
                readLock.lock();  
                  
            }  
            return value;  
              
        } catch (Exception e) {  
            e.printStackTrace();  
        }finally {  
            readLock.unlock();  
        }  
  
        return null;  
      
    }  
      
}

 

相關文章
相關標籤/搜索