Definition
讀寫鎖包含一對相關的鎖,讀鎖用於只讀操作,寫鎖用於寫操作。讀鎖可能由多個讀線程同時運行,寫鎖是唯一的。
Direction
1、讀鎖和寫鎖之間是互斥的,同一時間只能有一個在運行。但是可以有多個線程同時讀取數據。
2、寫入數據之前必須重新確認(ReCheck)狀態,因為其他的線程可能會拿到寫鎖再一次修改我們已經修改過的值。這是因為前一個線程拿到寫鎖之后,后面的線程會被阻塞。當前一個線程釋放寫鎖之后,被阻塞的線程會繼續運行完成被阻塞的部分代碼,所以才會出現這樣的情況。
3、當某一個線程上了寫鎖之后,自己仍然可以上讀鎖,之后在釋放寫鎖,這是一種降級(Downgrade)的處理方法。
Method
讀寫鎖(ReadWriteLock)包含如下兩個方法:
1.讀鎖
Lock readLock()
2.寫鎖
Lock writeLock()
Example
以下代碼在開始讀數據的時候上讀鎖,當有一個線程發現沒有數據時,釋放讀鎖,上寫鎖,開始寫入數據。
數據寫入完成后釋放寫鎖,並還原成讀鎖,實現了簡單的讀和寫之間的互斥。
示例代碼:
private ReadWriteLock rwl = new ReentrantReadWriteLock();//定義讀寫鎖 public Object getData(String key){ //使用讀寫鎖的基本結構 rwl.readLock().lock(); Object value = null; try{ value = cache.get(key); if(value == null){ rwl.readLock().unlock(); rwl.writeLock().lock(); try{ // Recheck state because another thread might have // acquired write lock and changed state before we did. if(value == null){ value = "aaaa";//寫入數據 } }finally{ rwl.writeLock().unlock(); } rwl.readLock().lock(); } }finally{ rwl.readLock().unlock(); } return value; }
讀寫鎖的完整使用示例:
1 public class Test { 2 public static void main(String[] args) { 3 final Queue q = new Queue(); 4 for(int i=0;i<3;i++) 5 { 6 new Thread(){ 7 public void run(){ 8 while(true){ 9 q.get(); 10 } 11 } 12 }.start(); 13 14 new Thread(){ 15 public void run(){ 16 while(true){ 17 q.put(new Random().nextInt(10000)); 18 } 19 } 20 }.start(); 21 } 22 } 23 } 24 25 class Queue{ 26 private Object data = null;//共享數據,只能有一個線程能寫該數據,但可以有多個線程同時讀該數據。 27 ReadWriteLock rwl = new ReentrantReadWriteLock(); 28 public void get(){ 29 rwl.readLock().lock(); 30 try { 31 System.out.println(Thread.currentThread().getName() + " be ready to read data!"); 32 Thread.sleep((long)(Math.random()*1000)); 33 System.out.println(Thread.currentThread().getName() + "have read data :" + data); 34 } catch (InterruptedException e) { 35 e.printStackTrace(); 36 }finally{ 37 rwl.readLock().unlock(); 38 } 39 } 40 41 public void put(Object data){ 42 rwl.writeLock().lock(); 43 try { 44 System.out.println(Thread.currentThread().getName() + " be ready to write data!"); 45 Thread.sleep((long)(Math.random()*1000)); 46 this.data = data; 47 System.out.println(Thread.currentThread().getName() + " have write data: " + data); 48 } catch (InterruptedException e) { 49 e.printStackTrace(); 50 }finally{ 51 rwl.writeLock().unlock(); 52 } 53 } 54 }
部分輸出結果如下:
Thread-0 be ready to read data! Thread-2 be ready to read data! Thread-4 be ready to read data! Thread-4have read data :null Thread-0have read data :null Thread-2have read data :null Thread-3 be ready to write data! Thread-3 have write data: 9763 Thread-3 be ready to write data! Thread-3 have write data: 5187 Thread-3 be ready to write data! Thread-3 have write data: 2135 Thread-1 be ready to write data! Thread-1 have write data: 180 Thread-1 be ready to write data! Thread-1 have write data: 5979 Thread-1 be ready to write data! Thread-1 have write data: 9495 Thread-1 be ready to write data! Thread-1 have write data: 6363 Thread-1 be ready to write data! Thread-1 have write data: 31 Thread-1 be ready to write data! Thread-1 have write data: 7530 Thread-1 be ready to write data! Thread-1 have write data: 1354 Thread-5 be ready to write data! Thread-5 have write data: 3580 Thread-5 be ready to write data! Thread-5 have write data: 5534 Thread-5 be ready to write data! Thread-5 have write data: 2522 Thread-5 be ready to write data! Thread-5 have write data: 2926 Thread-4 be ready to read data! Thread-0 be ready to read data! Thread-2 be ready to read data! Thread-2have read data :2926 Thread-0have read data :2926 Thread-4have read data :2926
