[英]Problems in MCS Lock Implementation - JAVA
我編寫了以下代碼(摘自《多處理器編程的藝術》一書):
package Chapter7;
import java.util.concurrent.atomic.AtomicReference;
public class MCSLock implements Lock {
AtomicReference<QNode> tail;
ThreadLocal<QNode> myNode;
public MCSLock() {
tail = new AtomicReference<>(null);
myNode = new ThreadLocal<QNode>() {
@Override
protected QNode initialValue() {
return new QNode();
}
};
}
@Override
@SuppressWarnings("empty-statement")
public void lock() {
QNode qnode = myNode.get();
QNode pred = tail.getAndSet(qnode);
if (pred != null) {
qnode.locked = true;
pred.next = qnode;
while (qnode.locked); // line A
}
}
@Override
@SuppressWarnings("empty-statement")
public void unlock() {
QNode qnode = myNode.get();
if (qnode.next == null) {
if (tail.compareAndSet(qnode, null)) {
return;
}
while (qnode.next == null); // line B
}
qnode.next.locked = false;
qnode.next = null;
}
class QNode {
boolean locked = false;
QNode next = null;
}
}
如果我使用少量線程和操作進行測試,這似乎可行,但是每次嘗試使用此鎖保護的每個線程使用8個線程和1000個操作時,它都會進入死鎖狀態。 我插入了一些打印來調試代碼,並插入了另一個線程來收集工作線程中的數據。 我找到:
該測試在簡單的PriorityQueue上完成。
此代碼的問題在於,它嘗試使用ThreadLocal
來實現線程限制。 但是,由於在鏈接列表中鏈接了QNodes
並通過next
引用和tail
引用來操縱實例,這破壞了線程的限制,並且在QNode
字段上沒有其他同步機制的情況下,不能保證更改在線程之間的可見性。
盡管qnode.next.locked = false;
,但繼續在A行循環是看到過時值的結果qnode.next.locked = false;
調用unlock()
。
類似地,盡管pred.next = qnode;
仍然繼續在B行循環是看到過時的值的pred.next = qnode;
調用lock()
。
在這兩種情況下,另一個線程的QNode
的字段QNode
發生突變。 在前一種情況下, qnode.next
,在后一種情況下, pred
是另一個線程的QNodes
。
如果在線程 pred.next
中運行set pred.next
,然后在不同步的qnode.next
在線程 qnode.next
中檢查qnode.next ,則由於內存屏障 , 線程_2可能永遠不會獲得您在線程_1中設置的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.