讀寫鎖ReadWriteLock
阿新 • • 發佈:2018-12-24
from URL : http://hi.baidu.com/zhizhesky/blog/item/cabcbb515b9b6808377abe5f.html
在上文中提到了Lock介面以及物件,使用它,很優雅的控制了競爭資源的安全訪問,但是這種鎖不區分讀寫,稱這種鎖為普通鎖。為了提高效能,Java提供了讀寫鎖,在讀的地方使用讀鎖,在寫的地方使用寫鎖,靈活控制,如果沒有寫鎖的情況下,讀是無阻塞的,在一定程度上提高了程式的執行效率。 Java中讀寫鎖有個介面java.util.concurrent.locks.ReadWriteLock,也有具體的實現ReentrantReadWriteLock,詳細的API可以檢視JavaAPI文件。
在上文中提到了Lock介面以及物件,使用它,很優雅的控制了競爭資源的安全訪問,但是這種鎖不區分讀寫,稱這種鎖為普通鎖。為了提高效能,Java提供了讀寫鎖,在讀的地方使用讀鎖,在寫的地方使用寫鎖,靈活控制,如果沒有寫鎖的情況下,讀是無阻塞的,在一定程度上提高了程式的執行效率。 Java中讀寫鎖有個介面java.util.concurrent.locks.ReadWriteLock,也有具體的實現ReentrantReadWriteLock,詳細的API可以檢視JavaAPI文件。
ReentrantReadWriteLock 和 ReentrantLock 不是繼承關係,但都是基於 AbstractQueuedSynchronizer 來實現。
lock方法 是基於CAS 來實現的
注意: 在同一執行緒中,持有讀鎖後,不能直接呼叫寫鎖的lock方法 ,否則會造成死鎖。
下面這個例子是在文例子的基礎上,將普通鎖改為讀寫鎖,並新增賬戶餘額查詢的功能,程式碼如下:- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.locks.ReadWriteLock;
-
import java.util.concurrent.locks.ReentrantReadWriteLock;
- /**
- publicclass Test {
- publicstaticvoid main(String[] args) {
- //建立併發訪問的賬戶
- MyCount myCount = new MyCount("95599200901215522", 10000);
- //建立一個鎖物件
- ReadWriteLock lock = new ReentrantReadWriteLock(false);
-
//建立一個執行緒池
- ExecutorService pool = Executors.newFixedThreadPool(2);
- //建立一些併發訪問使用者,一個信用卡,存的存,取的取,好熱鬧啊
- User u1 = new User("張三", myCount, -4000, lock, false);
- User u2 = new User("張三他爹", myCount, 6000, lock, false);
- User u3 = new User("張三他弟", myCount, -8000, lock, false);
- User u4 = new User("張三", myCount, 800, lock, false);
- User u5 = new User("張三他爹", myCount, 0, lock, true);
- //線上程池中執行各個使用者的操作
- pool.execute(u1);
- pool.execute(u2);
- pool.execute(u3);
- pool.execute(u4);
- pool.execute(u5);
- //關閉執行緒池
- pool.shutdown();
- }
- }
- /**
- class User implements Runnable {
- private String name; //使用者名稱
- private MyCount myCount; //所要操作的賬戶
- privateint iocash; //操作的金額,當然有正負之分了
- private ReadWriteLock myLock; //執行操作所需的鎖物件
- privateboolean ischeck; //是否查詢
- User(String name, MyCount myCount, int iocash, ReadWriteLock myLock, boolean ischeck) {
- this.name = name;
- this.myCount = myCount;
- this.iocash = iocash;
- this.myLock = myLock;
- this.ischeck = ischeck;
- }
- publicvoid run() {
- if (ischeck) {
- //獲取讀鎖
- myLock.readLock().lock();
- System.out.println("讀:" + name + "正在查詢" + myCount + "賬戶,當前金額為" + myCount.getCash());
- //釋放讀鎖
- myLock.readLock().unlock();
- } else {
- //獲取寫鎖
- myLock.writeLock().lock();
- //執行現金業務
- System.out.println("寫:" + name + "正在操作" + myCount + "賬戶,金額為" + iocash +",當前金額為" + myCount.getCash());
- myCount.setCash(myCount.getCash() + iocash);
- System.out.println("寫:" + name + "操作" + myCount + "賬戶成功,金額為" + iocash +",當前金額為" + myCount.getCash());
- //釋放寫鎖
- myLock.writeLock().unlock();
- }
- }
- }
- /**
- class MyCount {
- private String oid; //賬號
- privateint cash; //賬戶餘額
- MyCount(String oid, int cash) {
- this.oid = oid;
- this.cash = cash;
- }
- public String getOid() {
- return oid;
- }
- publicvoid setOid(String oid) {
- this.oid = oid;
- }
- publicint getCash() {
- return cash;
- }
- publicvoid setCash(int cash) {
- this.cash = cash;
- }
- @Override
- public String toString() {
- return"MyCount{" +
- "oid='" + oid + '\'' +
- ", cash=" + cash +
- '}';
- }
- }
- 寫:張三正在操作MyCount{oid='95599200901215522', cash=10000}賬戶,金額為-4000,當前金額為10000
- 寫:張三操作MyCount{oid='95599200901215522', cash=6000}賬戶成功,金額為-4000,當前金額為6000
- 寫:張三他弟正在操作MyCount{oid='95599200901215522', cash=6000}賬戶,金額為-8000,當前金額為6000
- 寫:張三他弟操作MyCount{oid='95599200901215522', cash=-2000}賬戶成功,金額為-8000,當前金額為-2000
- 寫:張三正在操作MyCount{oid='95599200901215522', cash=-2000}賬戶,金額為800,當前金額為-2000
- 寫:張三操作MyCount{oid='95599200901215522', cash=-1200}賬戶成功,金額為800,當前金額為-1200
- 讀:張三他爹正在查詢MyCount{oid='95599200901215522', cash=-1200}賬戶,當前金額為-1200
- 寫:張三他爹正在操作MyCount{oid='95599200901215522', cash=-1200}賬戶,金額為6000,當前金額為-1200
- 寫:張三他爹操作MyCount{oid='95599200901215522', cash=4800}賬戶成功,金額為6000,當前金額為4800
- Process finished with exit code 0