仅仅因为它很有趣,您还可以通过将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