JUC-Atomic 引用类型

原子引用

原子引用:对 Object 进行原子操作,提供一种读和写都是原子性的对象引用变量

原子引用类:AtomicReference、AtomicStampedReference、AtomicMarkableReference

AtomicReference 类:

  • 构造方法:AtomicReference<T> atomicReference = new AtomicReference<T>()

  • 常用 API:

    • public final boolean compareAndSet(V expectedValue, V newValue):CAS 操作
    • public final void set(V newValue):将值设置为 newValue
    • public final V get():返回当前值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class AtomicReferenceDemo {
public static void main(String[] args) {
Student s1 = new Student(33, "z3");

// 创建原子引用包装类
AtomicReference<Student> atomicReference = new AtomicReference<>();
// 设置主内存共享变量为s1
atomicReference.set(s1);

// 比较并交换,如果现在主物理内存的值为 z3,那么交换成 l4
while (true) {
Student s2 = new Student(44, "l4");
if (atomicReference.compareAndSet(s1, s2)) {
break;
}
}
System.out.println(atomicReference.get());
}
}

class Student {
private int id;
private String name;
//。。。。
}

AtomicStampedReference

如果主线程

希望:

只要有其它线程【动过了】共享变量,那么自己的 cas 就算失败,这时,仅比较值是不够的,需要再加一个版本号

AtomicStampedReference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

static AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);

public static void main(String[] args) throws InterruptedException {

log.debug("main start...");

// 获取值 A

String prev = ref.getReference();

// 获取版本号

int stamp = ref.getStamp();

log.debug("版本 {}", stamp);

// 如果中间有其它线程干扰,发生了 ABA 现象

other();

sleep(1);

// 尝试改为 C

log.debug("change A->C {}", ref.compareAndSet(prev, "C", stamp, stamp + 1));

}

private static void other() {

new Thread(() -> {

log.debug("change A->B {}", ref.compareAndSet(ref.getReference(), "B",

ref.getStamp(), ref.getStamp() + 1));

log.debug("更新版本为 {}", ref.getStamp());

}, "t1").start();

sleep(0.5);

new Thread(() -> {

log.debug("change B->A {}", ref.compareAndSet(ref.getReference(), "A",

ref.getStamp(), ref.getStamp() + 1));

log.debug("更新版本为 {}", ref.getStamp());

}, "t2").start();

}

输出为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

15:41:34.891 c.Test36 [main] - main start...

15:41:34.894 c.Test36 [main] - 版本 0

15:41:34.956 c.Test36 [t1] - change A->B true

15:41:34.956 c.Test36 [t1] - 更新版本为 1

15:41:35.457 c.Test36 [t2] - change B->A true

15:41:35.457 c.Test36 [t2] - 更新版本为 2

15:41:36.457 c.Test36 [main] - change A->C false

AtomicStampedReference 可以给原子引用加上版本号,追踪原子引用整个的变化过程,如: A -> B -> A -> C,通过AtomicStampedReference,我们可以知道,引用变量中途被更改了几次。

文章作者: GeYu
文章链接: https://nuistgy.github.io/2023/04/23/JUC-Atomic引用类型/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yu's Blog