舉例說明Java多線程編程中讀寫鎖的使用
以下示例為 java api并發(fā)庫中 ReentrantReadWriteLock自帶的實例,下面進行解讀
class CachedData {
Object data;
volatile boolean cacheValid;
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();//@1
if (!cacheValid) {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();//@4
rwl.writeLock().lock();//@2
// Recheck state because another thread might have acquired
// write lock and changed state before we did.
if (!cacheValid) {//@3
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();
rwl.writeLock().unlock(); // Unlock write, still hold read
}
use(data);
rwl.readLock().unlock();
}
}
當(dāng)有n多線程 使用同一CachedData 實例對象 調(diào)用processCachedData方法時,就會產(chǎn)生線程的并發(fā)問題.
@1行,當(dāng)有線程正在對數(shù)據(jù)進行 寫操作的時候,運行到@1行的線程要等待 寫操作的完成,因為第一個運行到@2的線程會加上鎖,然后對數(shù)據(jù)進行需該,期間不允許任何線程進行讀或者是寫的操作,
當(dāng)寫完后,在該線程上加上讀鎖操作,以防止解寫鎖后,別的線程對數(shù)據(jù)再次進行寫時出錯.在第一個運行到@2的線程之后的很多線程,
可能已經(jīng)運行到了@4,當(dāng)對數(shù)據(jù)修改好之后,解除掉寫鎖,別的線程就會執(zhí)行到@2,這時第一個線程已經(jīng)經(jīng)數(shù)據(jù)修改好了,所以有了@3的判斷。
在編寫多線程程序的時候,要置于并發(fā)線程的環(huán)境下考慮,巧妙的運用ReentrantReadWriteLock,在運用時,注意鎖的降級,寫入鎖可以獲得讀鎖,讀鎖不可以獲得寫入鎖,所以在上寫入鎖時,必須先將讀鎖進行解除,然后上讀鎖。
使用時注意的幾個方面:
讀鎖是排寫鎖操作的,讀鎖不排讀鎖操作,多個讀鎖可以并發(fā)不阻塞。即在讀鎖獲取后和讀鎖釋放之前,寫鎖并不能被任何線程獲得,
多個讀鎖同時作用期間,試圖獲取寫鎖的線程都處于等待狀態(tài),當(dāng)最后一個讀鎖釋放后,試圖獲取寫鎖的線程才有機會獲取寫鎖。
寫鎖是排寫鎖、排讀鎖操作的。當(dāng)一個線程獲取到寫鎖之后,其他試圖獲取寫鎖和試圖獲取讀鎖的線程都處于等待狀態(tài),直到寫鎖被釋放。
寫鎖是可以獲得讀鎖的,即:
rwl.writeLock().lock(); //在寫鎖狀態(tài)中,可以獲取讀鎖 rwl.readLock().lock(); rwl.writeLock().unlock();
讀鎖是不能夠獲得寫鎖的,如果要加寫鎖,本線程必須釋放所持有的讀鎖,即:
rwl.readLock().lock(); //...... //必須釋放掉讀鎖,才能夠加寫鎖 rwl.readLock().unlock(); rwl.writeLock().lock();
讀寫鎖是線程讀寫同一文件所需要用到的,讀寫鎖是什么東西在這里不做過多的解釋,可以自己去百度或谷歌去搜一下。
謹(jǐn)在此附上我自己寫的緩存系統(tǒng)的簡單實現(xiàn),你從中也能悟出緩存實現(xiàn)的基本思想
緩存里面有數(shù)據(jù)就從緩存中取,沒有就給你從其他地方得到。
package cn.com.scl.cache
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 緩存的實現(xiàn),每個線程只能獲得他自己的緩存,也應(yīng)該是單例的
* 本類沒有去實現(xiàn)單例,如果需要的話可以自行去實現(xiàn)
* @author scl
*
*/
public class CacheSystem {
private Map<String, Object> cache = new HashMap<String,Object>();
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public Object getData(String key){
//先從緩存中去取數(shù)據(jù),先加上讀鎖
rwl.readLock().lock();
Object obj = null;
try{
obj = cache.get(key);
if(obj == null){
//先解除讀鎖,在上寫鎖(必須先解除讀鎖才能成功上寫鎖)
rwl.readLock().unlock();
rwl.writeLock().lock();
//去數(shù)據(jù)庫取數(shù)據(jù),再判斷一次是否為null,因為有可能多個線程獲得寫鎖
try{
if(obj == null){
obj = new String("obj is get from db");
}
}finally{
//先上讀鎖,然后再解除寫鎖(這樣可以成功完成,在解除寫鎖前獲得讀鎖,寫鎖被降級--這翻譯的api上的)
rwl.readLock().lock();
rwl.writeLock().unlock();//解除寫鎖,讀鎖仍然持有
}
}
}finally{
rwl.readLock().unlock();
}
return obj;
}
}
上一篇:簡單實現(xiàn)C#異步操作
欄 目:C#教程
下一篇:dotNet中的反射用法入門教程
本文標(biāo)題:舉例說明Java多線程編程中讀寫鎖的使用
本文地址:http://m.jygsgssxh.com/a1/C_jiaocheng/6701.html
您可能感興趣的文章
- 01-10C#實現(xiàn)多線程下載文件的方法
- 01-10C#實現(xiàn)多線程寫入同一個文件的方法
- 01-10String.Format大全(C# Java)
- 01-10C#實現(xiàn)ComboBox控件顯示出多個數(shù)據(jù)源屬性的方法
- 01-10淺析JAVA中過濾器、監(jiān)聽器、攔截器的區(qū)別
- 01-10C#中實現(xiàn)一次執(zhí)行多條帶GO的sql語句實例
- 01-10C#類的多態(tài)性詳解
- 01-10C#中Equals方法的常見誤解
- 01-10C#實現(xiàn)向多線程傳參的三種方式實例分析
- 01-10C#基于委托實現(xiàn)多線程之間操作的方法


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻播放器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機閱讀
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10C#中split用法實例總結(jié)
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 04-02jquery與jsp,用jquery
- 01-10delphi制作wav文件的方法
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置


