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;
    }
}
相关推荐
Lee川8 小时前
mini-cursor 揭秘:从 Tool 定义到 Agent 循环的完整实现
前端·人工智能·后端
星浩AI10 小时前
OpenHuman 对比 OpenClaw、Hermes Agent
人工智能·后端·agent
小江的记录本10 小时前
【Java基础】泛型:泛型擦除、通配符、上下界限定(附《思维导图》+《面试高频考点清单》)
java·数据结构·后端·mysql·spring·面试·职场和发展
geovindu12 小时前
go: Semaphore Pattern
开发语言·后端·设计模式·golang·企业级信号量模式
IT_陈寒12 小时前
Redis内存用爆了,原来我们都忽略了这个配置
前端·人工智能·后端
武子康12 小时前
Java-02 深入浅出MyBatis 3 快速入门:环境配置、项目创建与 CRUD 操作
java·后端
未若君雅裁13 小时前
Spring Boot 自动配置原理与常用注解
java·spring boot·后端
Xiacqi113 小时前
Java数据库连接--JDBC--DRUID
数据库·后端
浮游本尊13 小时前
用结构化 Prompt 让大模型「干活」:以数据库巡检告警建议生成为例
后端
snakeshe101013 小时前
SpringBoot 多人协作平台实战(8):Cookie 与登录状态维持
后端