正确使用 AtomicReference.compareAndSet 进行堆栈实现

发布于 2024-10-30 02:31:46 字数 1053 浏览 1 评论 0原文

我正在尝试使用 java.util.concurrent 并尝试找出如何正确使用 AtomicReference.compareAndSet 来管理对单个共享状态单元的并发访问。

特别是:compareAndSet 的以下用法是否正确且安全?有什么陷阱吗?

我的测试类是一个基于节点链接列表的简单堆栈。

public class LinkedStack<T> {

  AtomicReference<Node<T>> topOfStack=new AtomicReference<Node<T>>();

  public T push(T e) {
    while(true) {
      Node<T> oldTop=topOfStack.get();
      Node<T> newTop=new Node<T>(e,oldTop);
      if (topOfStack.compareAndSet(oldTop, newTop)) break;
    } 
    return e;
  }

  public T pop() {
    while(true) {
      Node<T> oldTop=topOfStack.get();
      if (oldTop==null) throw new EmptyStackException();
      Node<T> newTop=oldTop.next;
      if (topOfStack.compareAndSet(oldTop, newTop)) return oldTop.object;
    } 
  }

  private static final class Node<T> {
    final T object;
    final Node<T> next;

    private Node (T object, Node<T> next) {
      this.object=object;
      this.next=next;
    }
  } 
  ...................
}

I was experimenting with java.util.concurrent and trying to work out how to use AtomicReference.compareAndSet correctly to manage concurrent access to a single unit of shared state.

In particular: is the following usage of compareAndSet correct and safe? Any pitfalls?

My test class is a simple stack based on a linked list of nodes.

public class LinkedStack<T> {

  AtomicReference<Node<T>> topOfStack=new AtomicReference<Node<T>>();

  public T push(T e) {
    while(true) {
      Node<T> oldTop=topOfStack.get();
      Node<T> newTop=new Node<T>(e,oldTop);
      if (topOfStack.compareAndSet(oldTop, newTop)) break;
    } 
    return e;
  }

  public T pop() {
    while(true) {
      Node<T> oldTop=topOfStack.get();
      if (oldTop==null) throw new EmptyStackException();
      Node<T> newTop=oldTop.next;
      if (topOfStack.compareAndSet(oldTop, newTop)) return oldTop.object;
    } 
  }

  private static final class Node<T> {
    final T object;
    final Node<T> next;

    private Node (T object, Node<T> next) {
      this.object=object;
      this.next=next;
    }
  } 
  ...................
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

山人契 2024-11-06 02:31:46

是的,这正是应该如何使用它。

也许下面的语法会更优雅:

Node<T> oldTop = null;
Node<T> newTop = null;
do {
    oldTop=topOfStack.get();
    newTop=new Node<T>(e,oldTop);
} while (!topOfStack.compareAndSet(oldTop, newTop));

Yes, that's exactly how it should be used.

Perhaps the following syntax would be more elegant:

Node<T> oldTop = null;
Node<T> newTop = null;
do {
    oldTop=topOfStack.get();
    newTop=new Node<T>(e,oldTop);
} while (!topOfStack.compareAndSet(oldTop, newTop));
梦亿 2024-11-06 02:31:46

它目前的形式是正确的。

您的结构称为 Treiber 堆栈。它是一个简单的线程安全的无锁结构,存在单点争用(topOfStack),因此往往会严重扩展(在争用情况下,它会崩溃,并且效果不佳)与 MMU)。如果争用可能较低但仍需要线程安全,那么这是一个不错的选择。

有关缩放堆栈算法的进一步阅读,请参阅“

It is correct in its current form.

Your structure is known as Treiber's Stack. It is a simple thread-safe lock-free structure that suffers from having a single point of contention (topOfStack) and therefore tends to scale badly (under contention it will thrash, and that doesn't play nicely with the MMU). It is a good option for if the contention is likely to be low but thread-safety is still required.

For further reading on scaling stack algorithms see "A Scalable Lock-free Stack Algorithm (pdf)" by Danny Hendler, Nir Shavit and Lena Yerushalmi.

み零 2024-11-06 02:31:46

一切看起来都不错(axtavt 所说的没什么新意),我认为值得注意的一件事是,失败的弹出或推送的比率现在是 ConcurrentLinkedQueue 的两倍。当我说失败时,我只是意味着您必须再次在 while 循环内执行,假设另一个线程在您之前弹出或推送。

尽管这可能超出了您想要实现的范围,但某种退避协议将有助于在高争用情况下提高性能。

It all looks good (nothing new from what axtavt said), the one thing I would think is worth noting is that the rate of a failed pop or push is now twice as high then with, say, a ConcurrentLinkedQueue. When I say fail I just mean you will have to execute within the while loop again, assuming another thread pops or pushes before you.

Though this may be out of scope of what you are trying to achieve, some kind of backoff protocol will help performance in the event of high contention.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文