目录页: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); 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