无锁线程安全栈的实现
import java.util.concurrent.atomic.AtomicReference;
public class LockFreeStack<T> {
private static class Node<T> {
final T item;
Node<T> next;
public Node(T item) {
this.item = item;
}
}
// 使用AtomicReference来保持栈顶节点的引用
private AtomicReference<Node<T>> head = new AtomicReference<>();
// 入栈操作
public void push(T item) {
Node<T> newNode = new Node<>(item);
Node<T> oldHead;
do {
oldHead = head.get(); // 获取当前的栈顶节点
newNode.next = oldHead; // 新节点指向旧的栈顶节点
// 尝试将新节点设置为栈顶节点,如果当前栈顶节点已经被其他线程更新,则重试
} while (!head.compareAndSet(oldHead, newNode));
}
// 出栈操作
public T pop() {
Node<T> oldHead;
Node<T> newHead;
do {
oldHead = head.get(); // 获取当前的栈顶节点
if (oldHead == null) {
return null; // 栈为空
}
newHead = oldHead.next; // 新的栈顶节点是当前栈顶节点的下一个节点
// 尝试将栈顶节点更新为新的栈顶节点,如果当前栈顶节点已经被其他线程更新,则重试
} while (!head.compareAndSet(oldHead, newHead));
return oldHead.item;
}
}
特点和说明
无锁(Lock-Free):这个栈的实现不使用传统的锁机制来保证线程安全,而是利用AtomicReference的CAS操作来原子地更新栈顶节点,从而实现无锁的线程安全。
性能:由于没有使用锁,避免了线程阻塞和唤醒带来的开销,特别是在高并发场景下,无锁数据结构通常能提供更好的性能。
重试机制:入栈和出栈操作在遇到并发冲突时会通过循环重试,直到成功为止。这种基于CAS的重试机制是无锁编程常用的策略之一。
通过这个示例,你可以看到AtomicReference如何在实现无锁数据结构时发挥作用,使得并发数据结构的设计既高效又线程安全。