我寫了一個Java lock free queue實現。它有一個併發錯誤。我找不到它。這段代碼並不重要。我只是擔心我無法解釋與揮發性變量相關的觀察行爲。鎖定空閒隊列中的錯誤在哪裏?
該錯誤是由異常(「空頭」)可見的。這是不可能的狀態,因爲存在保持當前隊列大小的原子整數。隊列中有一個存根元素。它規定讀者線程不會改變尾部指針,並且編寫器線程不會改變頭部指針。
隊列長度變量保證鏈表永遠不會爲空。這是一個信號量。
take方法的行爲就像它被盜的長度值。
class Node<T> {
final AtomicReference<Node<T>> next = new AtomicReference<Node<T>>();
final T ref;
Node(T ref) {
this.ref = ref;
}
}
public class LockFreeQueue<T> {
private final AtomicInteger length = new AtomicInteger(1);
private final Node stub = new Node(null);
private final AtomicReference<Node<T>> head = new AtomicReference<Node<T>>(stub);
private final AtomicReference<Node<T>> tail = new AtomicReference<Node<T>>(stub);
public void add(T x) {
addNode(new Node<T>(x));
length.incrementAndGet();
}
public T takeOrNull() {
while (true) {
int l = length.get();
if (l == 1) {
return null;
}
if (length.compareAndSet(l, l - 1)) {
break;
}
}
while (true) {
Node<T> r = head.get();
if (r == null) {
throw new IllegalStateException("null head");
}
if (head.compareAndSet(r, r.next.get())) {
if (r == stub) {
stub.next.set(null);
addNode(stub);
} else {
return r.ref;
}
}
}
}
private void addNode(Node<T> n) {
Node<T> t;
while (true) {
t = tail.get();
if (tail.compareAndSet(t, n)) {
break;
}
}
if (t.next.compareAndSet(null, n)) {
return;
}
throw new IllegalStateException("bad tail next");
}
}
當沒有使用鎖定機制時,此代碼如何防止數據競爭?你爲什麼不想使用鎖? – Chriss
你什麼時候看到問題?您是在單一閱讀器線程中獲得它,還是在看到問題之前需要多個閱讀器?我懷疑這個問題是圍繞在takeOrNull的第二個while循環中的多個讀者線程。 –
這不是生產代碼。對待這個練習。 –