# Java 比较和交换示例 – CAS 算法

> 原文： [https://howtodoinjava.com/java/multi-threading/compare-and-swap-cas-algorithm/](https://howtodoinjava.com/java/multi-threading/compare-and-swap-cas-algorithm/)

java 5 中最好的添加之一是`AtomicInteger`，`AtomicLong`等类中支持的原子操作。这些类可帮助您最大程度地减少对复杂（不必要） [**多线程**](//howtodoinjava.com/category/java/multi-threading/ "multi-threading")用于一些基本操作的代码，例如递增或递减在多个线程之间共享的值。 这些类在内部依赖于名为  CAS（比较和交换）的算法。 在本文中，我将详细讨论这个概念。

## 1.乐观锁和悲观锁

传统的锁定机制，例如，在 Java 中使用`syncronized`关键字的**被称为锁定或多线程的悲观技术**。 它要求您首先保证在特定操作之间没有其他线程会干扰（即锁定对象），然后仅允许您访问任何实例/方法。

> 这就像说“请先关上门； 否则，其他骗子会进来重新整理您的东西。”

尽管上述方法是安全的并且确实有效，但是**在性能**上对您的应用造成了重大损失。 原因很简单，等待线程无法做任何事情，除非它们也有机会执行受保护的操作。

还有一种方法在性能上更有效，并且**本质上是乐观的**。 通过这种方法，您可以进行更新，**希望可以完成更新而不会受到干扰**。 此方法依靠冲突检测来确定在更新期间是否存在来自其他方的干扰，在这种情况下，操作将失败并且可以重试（或不重试）。

> 乐观的方法就像老话所说：“获得宽容比得到许可更容易”，这里的“轻松”意味着“更有效率”。

**比较和交换**是这种乐观方法的一个很好的例子，我们将在下面讨论。

## 2.比较和交换算法

该算法将存储位置的内容与给定值进行比较，并且只有它们相同时，才会将该存储位置的内容修改为给定的新值。 这是作为单个原子操作完成的。 原子性保证了根据最新信息计算新值； 如果与此同时值已由另一个线程更新，则写入将失败。 操作的结果必须表明它是否执行了替换； 这可以通过简单的布尔响应（此变量通常称为“比较设置”）来完成，也可以通过返回从内存位置读取的值（而不是写入该值）来完成。

CAS 操作有 3 个参数：

1.  必须替换值的存储位置`V`
2.  线程上次读取的旧值`A`
3.  应该写在`V`上的新值`B` 

> CAS 说：“我认为`V`应该具有值`A`； 如果可以，则将`B`放在此处，否则不要更改它，但要告诉我我错了。” CAS 是一种乐观技术，它希望成功进行更新，并且自从上次检查变量以来，如果另一个线程更新了该变量，则可以检测到失败。

## 3\. Java 比较和交换示例

让我们通过一个例子来了解整个过程。 假设`V`是存储值“10”的存储位置。 有多个线程想要递增此值并将递增的值用于其他操作，这是一种非常实际的方案。 让我们分步介绍整个 CAS 操作：

**1）线程 1 和 2 想要增加它，它们都读取值并将其增加到 11。**

`V = 10，A = 0，B = 0`

**2）现在线程 1 首先出现，并将`V`与最后读取的值进行比较：**

`V = 10，A = 10，B = 11`

```java
if     A = V
   V = B
 else
   operation failed
   return V
```

显然，`V`的值将被覆盖为 11，即操作成功。

**3）线程 2 到来并尝试与线程 1 相同的操作**

`V = 11，A = 10，B = 11`

```java
if     A = V
   V = B
 else
   operation failed
   return V
```

**4）在这种情况下，`V`不等于`A`，因此不替换值，并且返回`V`即 11 的当前值。 现在线程 2，再次使用以下值重试此操作：**

`V = 11，A = 11，B = 12`

而这一次，条件得到满足，增量值 12 返回线程 2。

总而言之，当多个线程尝试使用 CAS 同时更新同一变量时，一个将获胜并更新该变量的值，而其余则将丢失。 但是失败者并不会因为线程中断而受到惩罚。 他们可以自由地重试该操作，或者什么也不做。

这就是与 Java 支持的原子操作有关的这个简单但重要的概念的全部。

**祝您学习愉快！**