CAS 是什么?原理及在双向链表中的应用
·
目录
一、CAS 简介
CAS(Compare and Swap)是一种用于实现并发控制的技术。它是一种乐观锁策略,常用于多线程环境下的数据同步操作。
(一)乐观锁与悲观锁
在并发编程中,锁是用于控制多个线程对共享资源的访问的机制。
- 悲观锁:假定在并发环境中,每次访问共享资源时都会发生冲突。因此,在访问资源之前,悲观锁会先获取锁,以确保同一时间只有一个线程能够访问资源。例如,Java 中的
synchronized关键字就是一种悲观锁机制。 - 乐观锁:则假定在并发环境中,大多数情况下访问共享资源不会发生冲突。乐观锁不会在访问资源之前加锁,而是在更新数据时检查数据是否被其他线程修改过。如果没有被修改过,则更新数据;如果被修改过,则根据具体情况采取相应的策略,如重试操作。
(二)CAS 操作原理
CAS 操作包含三个操作数:内存位置(V)、预期原值(A)和新值(B)。
- 当线程要更新变量的值时,它首先读取变量的当前值(V),并与预期原值(A)进行比较。
- 如果当前值(V)等于预期原值(A),则说明没有其他线程修改过该变量,此时线程可以将新值(B)写入内存位置(V)。
- 如果当前值(V)不等于预期原值(A),则说明有其他线程已经修改过该变量,此时线程不能直接更新变量的值,可能需要采取一些重试策略或者其他处理方式。
二、CAS 在双向链表中的应用
双向链表是一种常见的数据结构,它由一系列节点组成,每个节点包含指向前一个节点和后一个节点的指针。CAS 在双向链表中有着重要的应用,主要体现在以下几个方面。
(一)提高并发性能
在多线程环境下,如果多个线程同时对双向链表进行插入、删除或修改操作,使用 CAS 可以避免使用传统的锁机制带来的性能开销。
- 例如,当一个线程要在双向链表中插入一个节点时,它可以使用 CAS 操作来检查要插入位置的节点是否被其他线程修改过。如果没有被修改过,则可以安全地插入节点;如果被修改过,则可以重试操作。
- 这样可以允许多个线程同时对双向链表进行操作,而不需要像悲观锁那样阻塞其他线程的访问,从而提高了双向链表在并发环境下的操作效率。
(二)保证数据一致性
CAS 操作可以确保在多线程环境下双向链表的数据一致性。
- 当多个线程同时对双向链表进行操作时,通过 CAS 操作可以保证每个线程对链表的操作都是基于最新的链表状态进行的。
- 例如,在删除一个节点时,线程使用 CAS 操作来确保要删除的节点在操作过程中没有被其他线程修改过,从而避免了数据不一致的情况发生。
三、前端代码示例(Vue3 + TS)
以下是一个简单的 Vue3 + TS 前端代码示例,用于演示如何在前端中模拟 CAS 操作(这里只是一个概念性的模拟,实际应用场景可能会更加复杂)。
import { ref } from 'vue';
// 定义一个共享变量,模拟内存位置
const sharedValue = ref<number>(0);
// 定义一个函数,模拟CAS操作
function compareAndSwap(expectedValue: number, newValue: number): boolean {
if (sharedValue.value === expectedValue) {
sharedValue.value = newValue;
return true;
}
return false;
}
// 模拟两个线程同时操作共享变量
const thread1 = async () => {
const expected = 0;
const newValue = 1;
if (await compareAndSwap(expected, newValue)) {
console.log('Thread 1 updated the value successfully');
} else {
console.log('Thread 1 failed to update the value');
}
};
const thread2 = async () => {
const expected = 0;
const newValue = 2;
if (await compareAndSwap(expected, newValue)) {
console.log('Thread 2 updated the value successfully');
} else {
console.log('Thread 2 failed to update the value');
}
};
// 同时启动两个线程
(async () => {
await Promise.all([thread1(), thread2()]);
console.log('Final value:', sharedValue.value);
})();
四、后端代码示例(Java)
以下是一个 Java 后端代码示例,用于演示如何在 Java 中使用 CAS 操作。这里以AtomicInteger类为例,它内部使用了 CAS 操作来实现原子性的整数操作。
import java.util.concurrent.atomic.AtomicInteger;
public class CASExample {
public static void main(String[] args) {
// 定义一个AtomicInteger对象,用于模拟CAS操作
AtomicInteger atomicInteger = new AtomicInteger(0);
// 模拟两个线程同时操作AtomicInteger对象
Thread thread1 = new Thread(() -> {
int expected = 0;
int newValue = 1;
if (atomicInteger.compareAndSet(expected, newValue)) {
System.out.println("Thread 1 updated the value successfully");
} else {
System.out.println("Thread 1 failed to update the value");
}
});
Thread thread2 = new Thread(() -> {
int expected = 0;
int newValue = 2;
if (atomicInteger.compareAndSet(expected, newValue)) {
System.out.println("Thread 2 updated the value successfully");
} else {
System.out.println("Thread 2 failed to update the value");
}
});
// 启动两个线程
thread1.start();
thread2.start();
try {
// 等待两个线程执行完毕
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final value: " + atomicInteger.get());
}
}
五、Python 代码示例
以下是一个 Python 代码示例,用于演示如何在 Python 中模拟 CAS 操作。这里使用ctypes模块来访问 C 语言中的原子操作函数(在 Linux 系统下,Python 的ctypes模块可以直接访问libc.so.6库中的函数)。
import ctypes
import os
# 加载C语言标准库
libc = ctypes.CDLL(None if os.name == 'nt' else 'libc.so.6')
# 定义一个共享变量,模拟内存位置
shared_value = ctypes.c_int(0)
# 定义一个函数,模拟CAS操作
def compareAndSwap(expected_value, newValue):
global shared_value
return libc.__sync_bool_compare_and_swap(ctypes.byref(shared_value), expected_value, newValue)
# 模拟两个线程同时操作共享变量
def thread1():
expected = 0
newValue = 1
if compareAndSwap(expected, newValue):
print('Thread 1 updated the value successfully')
else:
print('Thread 1 failed to update the value')
def thread2():
expected = 0
newValue = 2
if compareAndSwap(expected, newValue):
print('Thread 2 updated the value successfully')
else:
print('Thread 2 failed to update the value')
# 同时启动两个线程
import threading
threading.Thread(target=thread1).start()
threading.Thread(target=thread2).start()
print('Final value:', shared_value.value)
通过以上介绍,我们了解了 CAS 的概念、原理以及它在双向链表中的应用,并给出了前端(Vue3 + TS)、后端(Java)和 Python 的代码示例。在实际应用中,需要根据具体的场景和需求来合理使用 CAS 操作,以实现高效的并发控制和数据一致性维护。
更多推荐


所有评论(0)