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


发布于 2020-04-14 / 1398 阅读 / 0 评论 /
一个Java5中最好添加的是支持类,如原子操作AtomicInteger,AtomicLong等等。这些课程帮助您最大限度地减少复杂的(非必要)需要多线程的,如增加一些基本的操作代码或递减的值在多个线程之间共享。这些类在内部依赖于名为CAS(比较和交换)的算法。在本文中,我将详细讨论这个概念。1.O

一个Java 5中最好添加的是支持类,如原子操作AtomicInteger,AtomicLong等等。这些课程帮助您最大限度地减少复杂的(非必要)需要多线程的,如增加一些基本的操作代码或递减的值在多个线程之间共享。这些类在内部依赖于名为CAS(比较和交换)的算法。在本文中,我将详细讨论这个概念。

1.Optimistic and Pessimistic Locking

传统的锁定机制,例如在Java中使用synced关键字,被称为是锁定或多线程的悲观技术。它要求您首先保证没有其他线程会干扰某些操作(即锁定对象),然后仅允许您访问任何实例/方法。

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

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

存在一种在性能上更有效并且本质上是乐观的方法。使用这种方法,您可以进行更新,希望可以在没有干扰的情况下完成更新。此方法依靠冲突检测来确定更新期间是否存在来自其他方的干扰,在这种情况下,操作将失败并且可以重试(或不重试)。

乐观的方法就像老话所说:“获得宽容比允许容易”,这里的“轻松”意味着“更有效”。

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

2.Compare and Swap Algorithm

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

CAS操作有3个参数:

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

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

3. Java Compare and Swap Example

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

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

V = 10,A = 0,B = 0

2)现在线程1首先出现,并将V与它的最后一个读取值进行比较:

V = 10,A = 10,B = 11

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

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

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

V = 11,A = 10,B = 11

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中支持的原子操作有关的这个简单但重要的概念的全部。

学习愉快!



是否对你有帮助?

评论