zoukankan      html  css  js  c++  java
  • ConcurrentLinkedQueue详解

    ConcurrentLinkedQueue详解

    简介

    实现线程安全的队列的两种方式:

    1. 使用阻塞算法:对入队和出队使用同一把锁(或不同的锁).
    2. 使用非阻塞算法:使用循环CAS方式实现.
    • ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列.
    • 采用先进先出规则对节点排序.
    • 添加元素会添加到队列的尾部,获取元素会返回队列头部元素.

    结构

    • 有两个结点:头节点(head)和尾节点(tail).
    • 每个节点由结点元素(item)和指向下一个节点的指针(next)组成.
    • 默认情况下head节点存储的元素为空,tail节点等于head节点.

    操作

    入队列

    将入队节点添加到队列尾部.

    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) {
                if (p.casNext(null, newNode)) {
                    if (p != t)
                        casTail(t, newNode);
                    return true;
                }
            }
            else if (p == q)
                p = (t != (t = tail)) ? t : head;
            else
                p = (p != t && t != (t = tail)) ? t : q;
        }
    }
    

    流程:

    1. 定位尾节点.
    2. 使用CAS将入队节点设置为尾节点的next节点,若不成功,则重试.

    定位尾节点:
    tail节点并非总是尾节点.每次入队必须先通过tail节点查找尾节点.

    设置入队节点为尾节点:
    设置入队节点为当前尾节点的next节点.

    • 刚开始head和tail节点都指向空节点.
    • 添加一个节点后,head和tail仍然指向空节点.
    • 再添加节点时,head指向空节点,tail指向尾节点.
    • 再次添加节点时,tail保持不变.
    • 再添加结点时,tail指向尾节点.

    出队列

    出队列是从队列中返回一个节点元素.

    public E poll() {
        restartFromHead:
        for (;;) {
            for (Node<E> h = head, p = h, q;;) {
                E item = p.item;
    
                if (item != null && p.casItem(item, null)) {
                    if (p != h)
                        updateHead(h, ((q = p.next) != null) ? q : p);
                    return item;
                }
                else if ((q = p.next) == null) {
                    updateHead(h, p);
                    return null;
                }
                else if (p == q)
                    continue restartFromHead;
                else
                    p = q;
            }
        }
    }
    

    流程:

    • 当head节点有元素时,直接弹出head节点对应的元素,不更新head节点.
    • 当head节点没有元素时,出队操作更新head节点.

    目的:减少使用CAS更新head节点的消耗,提高效率.

    • 先获取头节点的元素.
    • 再判断头节点元素是否为空.如果为空,则另外一个线程已进行出队操作.
    • 若不为空,则使用CAS方式将头节点的引用设为null.成功则直接返回头节点元素;不成功则其他线程已进行出队操作更新head节点,需重新获取头节点.

    参考:

  • 相关阅读:
    Spring配置文件中关于Shiro的配置
    关于Realm的源码分析
    配置SpringMVC配置
    Shiro的登录验证及授权多Realm情况【基于SpringMVC框架下】
    关于Nginx配置说明
    Hibernate中No row with the given identifier exists问题的原因及解决
    关于Shiro的角色授权
    关于Shiro的认证策略
    关于hibernate的cache总结及并发问题
    Shiro多Realm数据交互实现过程
  • 原文地址:https://www.cnblogs.com/truestoriesavici01/p/13214038.html
Copyright © 2011-2022 走看看