📜  实现CAS(比较和交换)算法的Java程序

📅  最后修改于: 2022-05-13 01:54:29.519000             🧑  作者: Mango

实现CAS(比较和交换)算法的Java程序

比较和交换是设计并发算法时使用的一种技术。该方法是将变量的实际值与变量的期望值进行比较,如果实际值与期望值匹配,则将变量的实际值与传入的新值交换。

要理解算法,必须具备Java中并发和多线程的基础知识。

算法的工作:

就好像我们知道这个变量应该是 1,我们想把它改成 2。由于这是一个多线程环境,我们知道其他人可能正在处理同一个变量。所以我们应该首先检查变量的值是否是我们认为的 1,如果是,那么我们将其更改为 2。如果我们看到变量现在是 3,那么这意味着其他人正在处理它,所以让我们这个时候不要碰它。

检查然后采取行动方法:-

并发问题最常见的情况是“先检查后行动”的方法。当代码首先检查变量的值,然后根据该值采取行动时,就会发生“先检查后行动”。这是一个简单的例子:

public boolean lock() {
    if(!locked) {
        lock = true;
        return true;
    }
    return false;
}

上面的代码是不安全的,因为如果两个或多个线程可能同时访问 lock()函数并进行检查,则不能保证上面的lock()函数工作,因为所有线程都会锁定资源并使用它就像它自己的一样。

让我们详细说明一下:

线程 A线程 B ,线程 B 可以在线程 A 检查锁定并看到它为假之间的任何时间检查锁定,线程 A 和线程 B 都可能看到锁定为假,然后两者都将根据那个信息。

上述问题可以通过使整个代码块同步来解决。然后只有一个线程(线程 A 或线程 B)一次进行检查并采取行动,只有在进入代码的线程完成其检查后,这是一项行动,然后另一个线程才能尝试。现在线程之间不会有误会了。

同步代码示例:

class GFG {

    private boolean locked = false;

    public synchronized boolean lock() {
        if(!locked) {
            locked = true;
            return true;
        }
        return false;
    }
}

现在 lock() 方法是同步的,因此一次只有一个线程可以在同一个 lock()函数上执行它。

原子操作

在Java 5 之后,我们不再需要使用检查和操作代码来实现或编写同步块, Java 5 通过Java.util.concurrent.atomic 提供这种支持:用于无锁、线程的类工具包对单个变量进行安全编程。

AtomicBoolean确保一次只有一个线程可以读取它。

这是一个示例,展示了如何使用AtomicBoolean实现 lock() 方法:

public static class MyLock {
    private AtomicBoolean locked = new AtomicBoolean(false);

    public boolean lock() {
        return locked.compareAndSet(false, true);
    }

}

请注意锁定变量如何不再是布尔值而是 AtomicBoolean。该类有一个compareAndSet()函数,该函数将 AtomicBoolean 实例的值与预期值进行比较,如果有预期值,则将该值与新值交换。在这种情况下,它将locked 的值与false 进行比较,如果为false,则将AtomicBoolean 的新值设置为true。

如果值被交换, compareAndSet() 方法返回 true,否则返回 false。

所以还有许多其他原子变量,例如:

  • AtomicInteger 此变量可让您以原子方式更新 int 值。
  • 原子长: 长具有线程安全的“比较和交换”功能。
  • 原子参考: 该变量提供了一个可以原子读写的对象引用变量。
  • AtomicIntegerArray、AtomicLongArray 和 AtomicReferenceArray

原子整数示例:

Java
// Java Program to demonstrates 
// the compareAndSet() function 
  
import java.util.concurrent.atomic.AtomicInteger; 
    
public class GFG { 
    public static void main(String args[]) 
    { 
    
        // Initially value as 0 
        AtomicInteger val = new AtomicInteger(0); 
    
        // Prints the updated value 
        System.out.println("Previous value: "
                           + val); 
    
        // Checks if previous value was 0 
        // and then updates it 
        boolean res = val.compareAndSet(0, 6); 
    
        // Checks if the value was updated. 
        if (res) 
            System.out.println("The value was"
                               + " updated and it is "
                               + val); 
        else
            System.out.println("The value was "
                               + "not updated"); 
    } 
}


输出
Previous value: 0
The value was updated and it is 6