Java线程详解(13)-锁
Java線程:新特征-鎖(上)
? ? ? ? 在Java5中,專門提供了鎖對象,利用鎖可以方便的實現資源的封鎖,用來控制對競爭資源并發訪問的控制,這些內容主要集中在java.util.concurrent.locks包下面,里面有三個重要的接口Condition、Lock、ReadWriteLock。
- Condition將Object監視器方法(wait、notify和?notifyAll)分解成截然不同的對象,以便通過將這些對象與任意Lock實現組合使用,為每個對象提供多個等待?set(wait-set)。??
- Lock實現提供了比使用synchronized方法和語句可獲得的更廣泛的鎖定操作。??
- ReadWriteLock維護了一對相關的鎖定,一個用于只讀操作,另一個用于寫入操作。??
????????舉個例子:
import?java.util.concurrent.ExecutorService;?? import?java.util.concurrent.Executors;?? import?java.util.concurrent.locks.Lock;?? import?java.util.concurrent.locks.ReentrantLock;??/**?*?Java線程:線程池-鎖?*/?? public?class?Test?{??public?static?void?main(String[]?args){??//創建并發訪問的賬戶??MyCount?myCount=new?MyCount("6215580000000000000",10000);??//創建一個鎖對象??Lock?lock=new?ReentrantLock();??//創建一個線程池??ExecutorService?pool?=?Executors.newCachedThreadPool();??//創建一些并發訪問用戶,一個信用卡,存的存,取的取??User?u1?=?new?User("張三",?myCount,?-4000,?lock);??User?u2?=?new?User("張三他爹",?myCount,?6000,?lock);??User?u3?=?new?User("張三他弟",?myCount,?-8000,?lock);??User?u4?=?new?User("張三",?myCount,?800,?lock);??//在線程池中執行各個用戶的操作??pool.execute(u1);??pool.execute(u2);??pool.execute(u3);??pool.execute(u4);??//關閉線程池??pool.shutdown();??}?? }?? //信用卡用戶?? class?User?implements?Runnable{??private?String?name;????????????????//用戶名??private?MyCount?myCount;????????//所要操作的賬戶??private?int?iocash;????????????????//操作的金額,當然有正負之分了??private?Lock?myLock;????????????????//執行操作所需的鎖對象??User(String?name,?MyCount?myCount,?int?iocash,?LockmyLock)?{??this.name?=?name;??this.myCount?=?myCount;??this.iocash?=?iocash;??this.myLock?=?myLock;??}??@Override??public?void?run()?{??//獲取鎖??myLock.lock();??//執行現金業務??System.out.println(name?+?"正在操作"?+?myCount?+"賬戶,金額為"?+?iocash?+",當前金額為"?+?myCount.getCash());??myCount.setCash(myCount.getCash()?+?iocash);??System.out.println(name?+?"操作"?+?myCount?+"賬戶成功,金額為"?+?iocash?+",當前金額為"?+?myCount.getCash());??//釋放鎖,否則別的線程沒有機會執行了??myLock.unlock();??}???? }?? //信用卡賬戶,可隨意透支?? class?MyCount?{??private?String?oid;????????//賬號??private?int?cash;????????????//賬戶余額??MyCount(String?oid,?int?cash)?{??this.oid?=?oid;??this.cash?=?cash;??}??public?String?getOid()?{??return?oid;??}??public?void?setOid(String?oid)?{??this.oid?=?oid;??}??public?int?getCash()?{??return?cash;??}??public?void?setCash(int?cash)?{??this.cash?=?cash;??}??@Override??public?String?toString()?{??return"MyCount{"?+??"oid='"?+?oid?+?'\''?+??",?cash="?+?cash?+??'}';??}?? }??
????????執行結果:
????????從上面的輸出可以看到,利用鎖對象太方便了,比直接在某個不知情的對象上用鎖清晰多了。
????????但一定要注意的是,在獲取了鎖對象后,用完后應該盡快釋放鎖,以便別的等待該鎖的線程有機會去執行
?
Java線程:新特征-鎖(下)
????????在上面提到了Lock接口以及對象,使用它,很優雅的控制了競爭資源的安全訪問,但是這種鎖不區分讀寫,稱這種鎖為普通鎖。為了提高性能,Java提供了讀寫鎖,在讀的地方使用讀鎖,在寫的地方使用寫鎖,靈活控制,在一定程度上提高了程序的執行效率。
????????Java中讀寫鎖有個接口java.util.concurrent.locks.ReadWriteLock,也有具體的實現ReentrantReadWriteLock,詳細的API可以查看JavaAPI文檔。
????????下面這個例子是在文例子的基礎上,將普通鎖改為讀寫鎖,并添加賬戶余額查詢的功能,代碼如下:
import?java.util.concurrent.ExecutorService;?? import?java.util.concurrent.Executors;?? import?java.util.concurrent.locks.ReadWriteLock;?? import?java.util.concurrent.locks.ReentrantReadWriteLock;??/**?*?Java線程:線程池-鎖?*/?? public?class?Test?{??public?static?void?main(String[]?args){??//創建并發訪問的賬戶??MyCount?myCount=new?MyCount("6215580000000000000",10000);??//創建一個鎖對象??ReadWriteLock?lock=new?ReentrantReadWriteLock(false);??//創建一個線程池??ExecutorService?pool?=?Executors.newCachedThreadPool();??//創建一些并發訪問用戶,一個信用卡,存的存,取的取??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;????????//所要操作的賬戶??private?int?iocash;????????????????//操作的金額,當然有正負之分了??private?ReadWriteLock?myLock;????????????????//執行操作所需的鎖對象??private?boolean?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;?? }??@Override??public?void?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;????????//賬號??private?int?cash;????????????//賬戶余額??MyCount(String?oid,?int?cash)?{??this.oid?=?oid;??this.cash?=?cash;??}??public?String?getOid()?{??return?oid;??}??public?void?setOid(String?oid)?{??this.oid?=?oid;??}??public?int?getCash()?{??return?cash;??}??public?void?setCash(int?cash)?{??this.cash?=?cash;??}??@Override??public?String?toString()?{??return"MyCount{"?+??"oid='"?+?oid?+?'\''?+??",cash="?+?cash?+??'}';??}?? }??
????????執行結果:
????????在實際開發中,最好在能用讀寫鎖的情況下使用讀寫鎖,而不要用普通鎖,以求更好的性能。
?
總結
以上是生活随笔為你收集整理的Java线程详解(13)-锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java线程详解(12)-有返回值的线程
- 下一篇: Java线程详解(14)-信号量