目录页:https://blog.csdn.net/u011294519/article/details/88367808
1. Compare and Swap [CAS]
1.1. 小声哔哔
之前学习的synchronized本质上是一种悲观锁,虽然的确安全有效,但是却牺牲了性能,原因大家也能想明白,等待锁的线程啥也干不了,直到获取锁。这也是HashTable不被待见的原因,翻看源码会发现一堆的synchronized(扯远了)。
那么问题来了,要啥自行车。Java为我们提供了CAS算法,一种乐观锁,我们希望在不受干扰的情况下进行更新操作,但是事实往往会有本山叔来要我们的自行车,CAS这种方法会进行冲突检测来判断更新期间是否有其他的干扰,以防被忽悠瘸了,在冲突检测中,如果发现操作失败我们可以选择重试或不重试,嗯,自行车保住了。
CAS算法将内存位置的内容与给定值进行比较,只有当它们相同时,才将该内存位置的内容修改为给定的新值。这是作为单个原子操作完成的。原子性保证了新值的计算是基于最新的信息;如果该值已由另一个线程同时更新,则写入将失败。操作结果必须表明是否执行了替换;这可以通过一个简单的布尔响应(这种变体通常称为比较和设置)来实现,也可以通过返回从内存位置读取的值(而不是写入其中的值)来实现。(我承认这段是抄的)。其实CAS是依赖于现在CPU的指令操作。
CAS的原子操作类包括:
更新基本数据类型在java.util.concurrent.atomic包下以Atomic开头的类。
下面只写几个示例代码
1.2. 更新基本类型:AtomicInteger
1.2.1. 主要方法
getAndIncrement():获取值后加一
getAndDecrement():获取值后减一
incrementAndGet():加一后获取值
decrementAndGet():减一后获取值
get():获取值
compareAndSet(int expect, int update):设置期望值之前比对更新值是否与内存中的值相同,若不相同返回false,若相同设置值并返回true
1.2.2. 上代码
package com.concurrent.coline.part7;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 类说明:AtomicInt
*/
public class UseAtomicInt {
static AtomicInteger ai = new AtomicInteger(10);
public static void main(String[] args) {
//10--->11
System.out.println(ai.getAndIncrement());
//11-->10
System.out.println(ai.getAndDecrement());
//10--->11
System.out.println(ai.incrementAndGet());
//11-->10
System.out.println(ai.decrementAndGet());
System.out.println(ai.get());
System.out.println(ai.compareAndSet(11, 10));
System.out.println(ai.compareAndSet(10, 10));
}
}
运行结果:
代码位置:compare-swap模块part7
1.3. 更新引用类型:AtomicReference
1.3.1. 主要方法
compareAndSet(int expect, int update):设置期望值之前比对更新值是否与内存中的值相同,若不相同返回false,若相同设置值 并返回true
1.3.2. 上代码
package com.concurrent.coline.part7;
import java.util.concurrent.atomic.AtomicReference;
/**
* 类说明:演示引用类型的原子操作类
*/
public class UseAtomicReference {
private static AtomicReference<UserInfo> userRef = new AtomicReference<UserInfo>();
public static void main(String[] args) {
//要修改的实体的实例
UserInfo user = new UserInfo("Tom", 15);
userRef.set(user);
//要变化的新实例
UserInfo updateUser = new UserInfo("Coline", 17);
System.out.println(userRef.compareAndSet(user, updateUser));
System.out.println(userRef.get().getName());
System.out.println(userRef.get().getAge());
System.out.println(user.getName());
System.out.println(user.getAge());
}
//定义一个实体类
private static class UserInfo {
private String name;
private int age;
private UserInfo(String name, int age) {
this.name = name;
this.age = age;
}
private String getName() {
return name;
}
private int getAge() {
return age;
}
}
}
运行结果:
可以看到这里的更新并不会修改user的实例
代码位置:compare-swap模块part7
1.4. 带版本戳更新:AtomicStampedReference
1.4.1. 说明
这个类是为了解决ABA问题而存在的,比如alpha线程想把A->B,但是beta线程做了A->B->A,在alpha线程来做操作的时候无法判断A被beta线程变过,也许我们就存在这样的业务场景,不允许alpha再进行业务修改,而是提醒我们(我想到的是类似于秘钥修改这种安全相关的场景),这时候将修改对象与版本相关联就成为了一种很好的解决方案。
1.4.2. 上代码
package com.concurrent.coline.part7;
import java.util.concurrent.atomic.AtomicStampedReference;
/**
* 类说明:演示带版本戳的原子操作类
*/
public class UseAtomicStampedReference {
private static AtomicStampedReference<String> asr =
new AtomicStampedReference<>("Coline", 0);
public static void main(String[] args) throws InterruptedException {
//获取初始的版本号
final int oldStamp = asr.getStamp();
final String oldReferenc = asr.getReference();
Thread rightStampThread = new Thread(() -> {
System.out.println(Thread.currentThread().getName()
+ "当前变量值:" + oldReferenc + "计划修改时版本戳:" + oldStamp + "-"
+ asr.compareAndSet(oldReferenc, oldReferenc + "Java",
oldStamp, oldStamp + 1));
});
Thread errorStampThread = new Thread(() -> {
System.out.println(Thread.currentThread().getName()
+ "当前变量值:" + oldReferenc + "计划修改时版本戳:" + oldStamp + "-"
+ asr.compareAndSet(oldReferenc, oldReferenc + "Java",
oldStamp, oldStamp + 1));
});
rightStampThread.start();
rightStampThread.join();
errorStampThread.start();
errorStampThread.join();
System.out.println(asr.getReference() + "===========" + asr.getStamp());
}
}
运行结果:
代码位置:compare-swap模块part7
1.5. 修改数组:AtomicIntegerArray
比较简单,直接上代码:
package com.concurrent.coline.part7;
import java.util.concurrent.atomic.AtomicIntegerArray;
/**
* 类说明:AtomicArray
*/
public class AtomicArray {
static int[] value = new int[]{1, 2};
static AtomicIntegerArray ai = new AtomicIntegerArray(value);
public static void main(String[] args) {
ai.getAndSet(0, 3);
System.out.println(ai.get(0));
System.out.println(value[0]);
}
}
运行结果:
代码位置:compare-swap模块part7