JAVA 无锁队列/栈

本文探讨了JAVA无锁队列/栈的实现原理和测试,包括无锁的CAP比较和交换机制、无锁队列的实现、CountDownLatch的简单介绍及其在测试中的应用。通过出队、入队、出栈、入栈的并发测试,验证了无锁数据结构在多线程环境中的线程安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

在多线程应用场景下,一般需要在代码中实现 加锁/解锁 操作来确保线程安全。在某些情况下,锁的处理会给程序带了很大的性能影响。在这种情况下, 我们就考虑无锁操作即在不加锁的情况下,依旧能保证线程的安全执行。


JAVA 无锁队列/栈 的实现

本篇就以下六个模块展开讨论:

  1. 无锁的原理
  2. 无锁队列的实现
  3. CountDownLatch简单介绍
  4. 无锁队列的测试
  5. 无锁栈的实现
  6. 无锁栈的测试

1、无锁的原理

无锁的实现原理是 “CAP”(Campare and swap)。翻译过来即“比较和交换”。

关于 CAP 的实现原理本篇我们不详细展开论述,在后面的文章专门介绍。下面主要介绍一下 CAP 的核心方法:compareAndSet ()

在代码中该方法一般是这样调用的:

a.compareAndSet(oldValue, newValue)

其中 oldValue 表示老值,newValue 表示新值,该方法执行的结果有以下两种:

  1. 如果变量a的值此时和 oldValue 相等,那么将 newValue 赋予它,并返回 True。
  2. 如果变量a的值此时和 oldValue 不相等,那么它不做任何操作,并返回 False。

其中为了进行循环判断,该方法一般和while循环结合使用,这也就是我们常称的 自旋锁

的作用是保证同一时刻最多只能有一个线程操作某块内存,其他线程只能等到该线程处理完毕后进行读写操作。

无锁 是无法保证某块内存在同一时刻不被多个线程共享,它是在写内存过程前提供一个期望值,如果期望值与当前值相等,说明该线程上一次读取值之后,没有其他线程对这块内存进行处理,也就是说该操作是线程安全的

通过上面的概述其实我们不难发现,无锁还是存在以下隐患的:即操作的内存被其他线程操作两次,最终又返回原值时,无锁是无法判断是否有线程处理过该块内存的,但这种场景一般不影响结果

举例:变量a = 5,现在有两个线程处理变量a,线程1要将它的值+5,线程2要将它的值+10,我们使用无锁来模拟这种场景下可能产生的情况:

Created with Raphaël 2.2.0 开始 线程1读取值5 线程2读取值5 线程2进行运算,得到新值15 线程2判断旧值为5,将新值15赋予变量并返回true 线程1进行运算,得到新值10 线程1判断旧值不为5,停止操作并返回false 结束

2、无锁队列的实现

这里我直接贴出代码,通过注释的方式列举出每种操作对应的场景:

public class CapQueue<V> {
   

    /**
     * 模拟队列中的节点,通过 next属性相连接
     *
     * @param <V>
     */
    private class Node<V> {
   
        // 具体的值
        private V value;
        // 模拟队列中节点相连接
        private AtomicReference<Node<V>> next;

        public Node(V value, Node<V> next) {
   
            this.value = value;
            this.next = new AtomicReference<>(next);
        }
    }

    /**
     * 队列头,其中 head不计算在队列中
     */
    private AtomicReference<Node<V>> head = null;
    /**
     * 队列尾,标记队尾元素
     */
    private AtomicReference<Node<V>> tail = null;
    /**
     * 队列大小
     */
    private AtomicInteger queueSize = new AtomicInteger(0);

    public CapQueue() {
   
        // 初始化队列头和尾
        Node<V> node = new Node<>(null, null);
        head = new AtomicReference<>(node);
        tail = new AtomicReference<>(node);
    }

    /**
     * 入队操作
     *
     * @param value
     */
    public void enQueue(V value) {
   
        Node<V> newNode = new Node<>(value, null);
        Node
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值