併發 讀寫鎖初探

2021-09-13 16:48:07 字數 3470 閱讀 3925

public class readwritelock

readers++;

}public synchronized void unlockread()

public synchronized void lockwrite() throws interruptedexception

writerequests--;

writers++;

}public synchronized void unlockwrite() throws interruptedexception

}readwritelockl類中通過讀鎖、寫鎖以兩個鎖的狀態控制線程的讀、寫操作:

writers表示當前正在使用寫鎖的執行緒數量;

writerequests表示等待請求寫鎖的執行緒數量;

readers表示請求讀鎖的執行緒數量;

說明:

1.執行緒在獲取讀鎖的時候,只要沒有執行緒擁有寫鎖即writers==0同時沒有執行緒請求寫鎖即writerrquests==0,那麼執行緒就能成功獲取讀鎖;

2.當乙個執行緒想獲取寫鎖的時候,會把寫鎖的請求數加1即writerequests++,然後再嘗試獲取能否獲取寫鎖,如果當前沒有執行緒占用寫鎖即writers==0,那麼此時就能成功獲取寫鎖,同時writers++;如果wirters>0表示寫鎖此時被其他執行緒占用那麼當前執行緒會被阻塞等待寫鎖釋放時被喚醒。

3.寫操作的優先順序高於讀操作的優先順序體現在,執行緒請求讀鎖時會判斷持有寫鎖的執行緒數和請求寫鎖的執行緒數,即while(writers > 0 || writerequests > 0),而執行緒請求寫鎖時只需要判斷持有寫鎖和讀鎖的執行緒數即可,即while(readers > 0 || writers > 0)

鎖重入,是指同一執行緒 外層函式獲得鎖之後 ,內層遞迴函式仍然有獲取該鎖的**,但不受影響。reentrantlock 和synchronized 都是可重入鎖,可重入鎖最大的作用是避免死鎖。

以自旋鎖為例,如果自旋鎖不是可重入鎖的話,如果乙個執行緒在第一次獲取鎖執行同步**前提下,第二次再執行同步**就產生了死鎖。

以前面的**為例:

此時有兩個執行緒thread1,thread2

thread2在thread1獲取讀鎖以後請求寫鎖,readers=1、writers=0、writerequests=1

若此時thread1再次嘗試獲取同乙個讀鎖,根據已有的**writers > 0 || writerequests > 0,因為thread請求寫鎖的原因導致該條件成立,thread1進入阻塞狀態,死鎖出現

public class readwritelock

readingthreads.put(callingthread, (getaccesscount(callingthread) + 1));

}public synchronized void unlockread() else

notifyall();

}private boolean cangrantreadaccess(thread callingthread)

private int getreadaccesscount(thread callingthread)

private boolean isreader(thread callingthread)

}讀鎖的可重入有兩種情況:

1.當前程式中沒有執行緒請求寫鎖(這種情況是幾乎不存在)

2.當前程式中有執行緒請求寫鎖也有執行緒請求讀鎖,並且有執行緒已經得到了讀鎖

第二種情況是最常見的,因此我們需要知道哪些執行緒是持有讀鎖的

因此在**中使用map來儲存已經持有讀鎖的執行緒和對應執行緒獲取讀鎖的次數,通過map就可以判斷對應的執行緒是否持有讀鎖,調整之後的**在原有判斷"writerequests >0"和"writers > 0"還加上了判斷當前執行緒是否持有讀鎖的判斷邏輯

public class readwritelock

writerequests--;

writeaccesses++;

writingthread = callingthread;

}public synchronized void unlockwrite() throws interruptedexception

notifyall();

}private boolean cangrantwriteaccess(thread callingthread)

private boolean hasreaders()

private boolean iswriter(thread callingthread)

} 寫鎖重入,是在當前程式裡有且只有乙個執行緒持有寫鎖,如果寫鎖重入,說明當前程式中沒有執行緒持有讀鎖,寫鎖重入只有持有寫鎖的執行緒才能重入,其他的執行緒就需要進入阻塞狀態

public class readwritelock

readingthreads.put(callingthread,(getreadaccesscount(callingthread) + 1));

}private boolean cangrantreadaccess(thread callingthread)

public synchronized void unlockread()

int accesscount = getreadaccesscount(callingthread);

if(accesscount == 1) else

notifyall();

}public synchronized void lockwrite() throws interruptedexception

writerequests--;

writeaccesses++;

writingthread = callingthread;

}public synchronized void unlockwrite() throws interruptedexception

writeaccesses--;

if(writeaccesses == 0)

notifyall();

}private boolean cangrantwriteaccess(thread callingthread)

private int getreadaccesscount(thread callingthread)

private boolean hasreaders()

private boolean isreader(thread callingthread)

private boolean isonlyreader(thread callingthread)

private boolean haswriter()

private boolean iswriter(thread callingthread)

private boolean haswriterequests()

}

參考文獻

併發 讀寫鎖初探

兩個執行緒同時讀取同乙個共享資源沒有任何問題 如果乙個執行緒對共享資源進行寫操作,此時就不能有其他執行緒對共享資源進行讀寫 讀操作觸發條件 沒有執行緒正在執行寫操作 沒有執行緒在等待執行寫操作 寫操作觸發條件 沒有執行緒正在執行讀寫操作 readwritelockl類中通過讀鎖 寫鎖以兩個鎖的狀態控...

Java併發之讀 寫鎖

讀取 沒有執行緒正在做寫操作且沒有執行緒請求寫操作 寫入 沒有執行緒正在做寫操作 這裡假設寫操作的優先順序比讀操作高 當乙個執行緒已經擁有寫鎖,才允許寫鎖重入 public class readwritelock writerequest writeaccesses writingthread ca...

Java併發 讀寫鎖ReadWriteLock

讀寫鎖是為了幫助解決多執行緒中讀操作和寫操作分離而設計的。想象一下,如果在系統中,讀操作遠遠大於寫操作,而每一次寫操作進行時,別的寫操作也要等待,這樣對系統的效能會有很大的影響。readwritelock是jdk5開始提供的讀寫分離鎖。讀寫鎖允許多個執行緒同時讀,是的讀執行緒可以真正的並行。但是考慮...