192_如何基于复杂的指针移动完成单向链表的入队?

基于CAS实现的线程并发安全性,非阻塞

LinkedQueue,底层一定是基于链表来实现的,所以一定会有Node类数据结构,Node指向对方串成一个链表,单向的,双向的,head和tail两个指针都是指向了链表中的头节点和尾节点

csharp 复制代码
if (p.casNext(null, newNode)) {
kotlin 复制代码
boolean casNext(Node<E> cmp, Node<E> val) {
    return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}

这是一个CAS操作,就是把空节点的next指针指向了新的节点,同一时间只有一个线程可以执行成功这个操作

此时如果再次往队列里入队一个李四元素

此时如果再次往队列里入队一个王五元素

arduino 复制代码
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
queue.offer("张三");
queue.offer("李四");
queue.offer("王五");
System.out.println(queue.poll());
System.out.println(queue);
csharp 复制代码
public ConcurrentLinkedQueue() {
    head = tail = new Node<E>(null);
}
arduino 复制代码
private static class Node<E> {
    volatile E item;
    volatile Node<E> next;

    /**
     * Constructs a new node.  Uses relaxed write because item can
     * only be seen after publication via casNext.
     */
    Node(E item) {
        UNSAFE.putObject(this, itemOffset, item);
    }

    boolean casItem(E cmp, E val) {
        return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
    }

    void lazySetNext(Node<E> val) {
        UNSAFE.putOrderedObject(this, nextOffset, val);
    }

    boolean casNext(Node<E> cmp, Node<E> val) {
        return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
    }

    // Unsafe mechanics

    private static final sun.misc.Unsafe UNSAFE;
    private static final long itemOffset;
    private static final long nextOffset;

    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> k = Node.class;
            itemOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("item"));
            nextOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("next"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }
}
scss 复制代码
public boolean offer(E e) {
    checkNotNull(e);
    final Node<E> newNode = new Node<E>(e);

    for (Node<E> t = tail, p = t;;) {
        Node<E> q = p.next;
        if (q == null) {
            // p is last node
            if (p.casNext(null, newNode)) {
                // Successful CAS is the linearization point
                // for e to become an element of this queue,
                // and for newNode to become "live".
                if (p != t) // hop two nodes at a time
                    casTail(t, newNode);  // Failure is OK.
                return true;
            }
            // Lost CAS race to another thread; re-read next
        }
        else if (p == q)
            // We have fallen off list.  If tail is unchanged, it
            // will also be off-list, in which case we need to
            // jump to head, from which all live nodes are always
            // reachable.  Else the new tail is a better bet.
            p = (t != (t = tail)) ? t : head;
        else
            // Check for tail updates after two hops.
            p = (p != t && t != (t = tail)) ? t : q;
    }
}
相关推荐
Bazingga13 分钟前
从0到1搭一个Agent:Spring AI显式ReAct循环完整实战
后端
LEE16 分钟前
前端转型全栈 05:SQL 与迁移,AI 写的 SQL 怎么安全上线
前端·后端·ai编程
站大爷IP17 分钟前
Python的列表删除把我坑惨了,原来remove和pop的区别这么大
后端
montEvergreen27 分钟前
RTMP 王国的“信笺百科全书”
后端·go
北冥you鱼27 分钟前
Go 语言 Channel 机制详解:从原理到实战
开发语言·后端·golang
杨利杰YJlio29 分钟前
Tibo的28天计划DAY1GPT-6提速50%意味着什么?
前端·javascript·后端
谢亮_vipxieliang30 分钟前
Go 并发控制进阶:sync 包高级原语与 Context 生命周期管理
开发语言·后端·golang
你顶住我先撤1 小时前
RocketMQ 存储机制
后端
用户9479135811621 小时前
ReAct 到底在循环什么:从零拆解 Agent 的「想一步、做一步」机制
后端
TechLee1 小时前
Go 泛型统一 API 响应设计的最佳实践
后端·架构·go