1. 程式人生 > >讀寫鎖ReadWriteLock

讀寫鎖ReadWriteLock

from URL : http://hi.baidu.com/zhizhesky/blog/item/cabcbb515b9b6808377abe5f.html

在上文中提到了Lock介面以及物件,使用它,很優雅的控制了競爭資源的安全訪問,但是這種鎖不區分讀寫,稱這種鎖為普通鎖。為了提高效能,Java提供了讀寫鎖,在讀的地方使用讀鎖,在寫的地方使用寫鎖,靈活控制,如果沒有寫鎖的情況下,讀是無阻塞的,在一定程度上提高了程式的執行效率。 Java中讀寫鎖有個介面java.util.concurrent.locks.ReadWriteLock,也有具體的實現ReentrantReadWriteLock,詳細的API可以檢視JavaAPI文件。

ReentrantReadWriteLock 和 ReentrantLock 不是繼承關係,但都是基於 AbstractQueuedSynchronizer 來實現。

lock方法 是基於CAS 來實現的

注意: 在同一執行緒中,持有讀鎖後,不能直接呼叫寫鎖的lock方法 ,否則會造成死鎖。

下面這個例子是在文例子的基礎上,將普通鎖改為讀寫鎖,並新增賬戶餘額查詢的功能,程式碼如下:
  1. import java.util.concurrent.ExecutorService;  
  2. import java.util.concurrent.Executors;  
  3. import java.util.concurrent.locks.ReadWriteLock;  
  4. import java.util.concurrent.locks.ReentrantReadWriteLock;  
  5. /**  
  6. publicclass Test {  
  7.          publicstaticvoid main(String[] args) {  
  8.                  //建立併發訪問的賬戶
  9.                  MyCount myCount = new MyCount("95599200901215522"10000);  
  10.                  //建立一個鎖物件
  11.                  ReadWriteLock lock = new ReentrantReadWriteLock(false);  
  12.                  //建立一個執行緒池
  13.                  ExecutorService pool = Executors.newFixedThreadPool(2);  
  14.                  //建立一些併發訪問使用者,一個信用卡,存的存,取的取,好熱鬧啊
  15.                  User u1 = new User("張三", myCount, -4000, lock, false);  
  16.                  User u2 = new User("張三他爹", myCount, 6000, lock, false);  
  17.                  User u3 = new User("張三他弟", myCount, -8000, lock, false);  
  18.                  User u4 = new User("張三", myCount, 800, lock, false);  
  19.                  User u5 = new User("張三他爹", myCount, 0, lock, true);  
  20.                  //線上程池中執行各個使用者的操作
  21.                  pool.execute(u1);  
  22.                  pool.execute(u2);  
  23.                  pool.execute(u3);  
  24.                  pool.execute(u4);  
  25.                  pool.execute(u5);  
  26.                  //關閉執行緒池
  27.                  pool.shutdown();  
  28.          }  
  29. }  
  30. /**  
  31. class User implements Runnable {  
  32.          private String name;                 //使用者名稱
  33.          private MyCount myCount;         //所要操作的賬戶
  34.          privateint iocash;                 //操作的金額,當然有正負之分了
  35.          private ReadWriteLock myLock;                 //執行操作所需的鎖物件
  36.          privateboolean ischeck;         //是否查詢
  37.          User(String name, MyCount myCount, int iocash, ReadWriteLock myLock, boolean ischeck) {  
  38.                  this.name = name;  
  39.                  this.myCount = myCount;  
  40.                  this.iocash = iocash;  
  41.                  this.myLock = myLock;  
  42.                  this.ischeck = ischeck;  
  43.          }  
  44.          publicvoid run() {  
  45.                  if (ischeck) {  
  46.                          //獲取讀鎖
  47.                          myLock.readLock().lock();  
  48.                          System.out.println("讀:" + name + "正在查詢" + myCount + "賬戶,當前金額為" + myCount.getCash());  
  49.                          //釋放讀鎖
  50.                          myLock.readLock().unlock();  
  51.                  } else {  
  52.                          //獲取寫鎖
  53.                          myLock.writeLock().lock();  
  54.                          //執行現金業務
  55.                          System.out.println("寫:" + name + "正在操作" + myCount + "賬戶,金額為" + iocash +",當前金額為" + myCount.getCash());  
  56.                          myCount.setCash(myCount.getCash() + iocash);  
  57.                          System.out.println("寫:" + name + "操作" + myCount + "賬戶成功,金額為" + iocash +",當前金額為" + myCount.getCash());  
  58.                          //釋放寫鎖
  59.                          myLock.writeLock().unlock();  
  60.                  }  
  61.          }  
  62. }  
  63. /**  
  64. class MyCount {  
  65.          private String oid;         //賬號
  66.          privateint cash;             //賬戶餘額
  67.          MyCount(String oid, int cash) {  
  68.                  this.oid = oid;  
  69.                  this.cash = cash;  
  70.          }  
  71.          public String getOid() {  
  72.                  return oid;  
  73.          }  
  74.          publicvoid setOid(String oid) {  
  75.                  this.oid = oid;  
  76.          }  
  77.          publicint getCash() {  
  78.                  return cash;  
  79.          }  
  80.          publicvoid setCash(int cash) {  
  81.                  this.cash = cash;  
  82.          }  
  83.          @Override
  84.          public String toString() {  
  85.                  return"MyCount{" +  
  86.                                  "oid='" + oid + '\'' +  
  87.                                  ", cash=" + cash +  
  88.                                  '}';  
  89.          }  
  90. }  
  91. 寫:張三正在操作MyCount{oid='95599200901215522', cash=10000}賬戶,金額為-4000,當前金額為10000
  92. 寫:張三操作MyCount{oid='95599200901215522', cash=6000}賬戶成功,金額為-4000,當前金額為6000
  93. 寫:張三他弟正在操作MyCount{oid='95599200901215522', cash=6000}賬戶,金額為-8000,當前金額為6000
  94. 寫:張三他弟操作MyCount{oid='95599200901215522', cash=-2000}賬戶成功,金額為-8000,當前金額為-2000
  95. 寫:張三正在操作MyCount{oid='95599200901215522', cash=-2000}賬戶,金額為800,當前金額為-2000
  96. 寫:張三操作MyCount{oid='95599200901215522', cash=-1200}賬戶成功,金額為800,當前金額為-1200
  97. 讀:張三他爹正在查詢MyCount{oid='95599200901215522', cash=-1200}賬戶,當前金額為-1200
  98. 寫:張三他爹正在操作MyCount{oid='95599200901215522', cash=-1200}賬戶,金額為6000,當前金額為-1200
  99. 寫:張三他爹操作MyCount{oid='95599200901215522', cash=4800}賬戶成功,金額為6000,當前金額為4800
  100. Process finished with exit code 0