僅僅因爲它很有趣,您還可以通過將head
彈出爲AtomicReference並完全避免來使此線程安全。正是如此:
final class Stack {
private val head = new AtomicReference[Node](Nil)
@tailrec
def push(newValue: Int) {
val current = head.get()
if (!head.compareAndSet(current, Node(newValue, current))) {
push(newValue)
}
}
@tailrec
def pop(): Option[Int] = head.get() match {
case current @ Cons(v, tail) => {
if (!head.compareAndSet(current, tail))
pop()
else
Some(v)
}
case Nil => None
}
def size = {
def loop(node: Node, size: Int): Int = node match {
case Cons(_, tail) => loop(tail, size + 1)
case Nil => size
}
loop(head.get(), 0)
}
private sealed trait Node
private case class Cons(head: Int, tail: Node) extends Node
private case object Nil extends Node
}
這避免完全鎖定,並提供比版本大幅提高吞吐量。值得注意的是,這種假線程安全的數據結構很少是一個好主意。在數據結構級別處理同步和狀態管理問題有點像嘗試處理XML解析器中的IO異常:您試圖在錯誤的地方解決正確的問題,並且您沒有所需的信息去做。例如,上面的堆棧非常安全,但在操作中它肯定不一致(例如,您可以推入並隨後彈出到堆棧並因此得到None
)。
你更好的選擇是使用一個不變的堆棧(如List
),並拋出是爲AtomicReference
,如果你需要共享的可變狀態。
那麼,爲什麼它不是線程安全的?你有什麼努力使它成爲線程安全的? –
(這個問題不僅僅是'sz':記住,它是操作以及如何使用它們必須是原子的。) – 2011-11-29 22:30:53