JAVA的原子性、可见性、有序性

原子性

定义

是指一个操作或多个操作要么全部执行,且执行的过程不会被任何因素打断,要么都不执行。

原子操作原理(处理器是如何实现原子操作的)

处理器实现原子操作有3种方式:

  1. 处理器自动保证基本内存操作的原子性
  2. 使用总线锁保证原子性
  3. 使用缓存锁保证原子性

可见性

定义

可见性是指:当一个线程修改了线程共享变量的值,其它线程能够立即得知这个修改。

Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方法来实现可见性的,无论是普通变量还是volatile变量都是如此。

普通变量与volatile变量的区别

是volatile的特殊规则保证了新值能立即同步到主内存,以及每使用前立即从内存刷新。因为我们可以说volatile保证了线程操作时变量的可见性,而普通变量则不能保证这一点。

有序性

定义

有序性:即程序执行的顺序按照代码的先后顺序执行。

Java内存模型中的程序天然有序性可以总结为一句话:如果在本线程内观察,所有操作都是有序的;如果在一个线程中观察另一个线程,所有操作都是无序的。 前半句是指“线程内表现为串行语义”,后半句是指“指令重排序”现象和“工作内存主主内存同步延迟”现象。

有序性的语意有几层,

  1. 最常见的就是保证多线程运行的串行顺序
  2. 防止重排序引起的问题
  3. 程序运行的先后顺序。比方JMM定义的一些Happens-before规则

实例

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
public class MyClass {

private static volatile int count = 0;
private static AtomicInteger atomicCount = new AtomicInteger(0);
private static int synchronizedCount = 0;

public static void main(String[] args) {
// 分别调用,打印结果
// volatileCount();
// atomicCount();
synchronizedCount();
}

private static void volatileCount() {
for (int i = 0; i < 10; i++) {
Executors.newFixedThreadPool(3).execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 虽然使用volatile关键字修饰int变量,但是对于多线程的环境下,也很难保证没问题,所以一般用来修饰标志位
System.out.println("volatile count: " + ++count);
}
});
}
}
// 打印结果:有重复数据,且顺序错乱。表示数据操作不是原子的,线程之间也不是有序的
// volatile count: 1
// volatile count: 5
// volatile count: 4
// volatile count: 3
// volatile count: 1
// volatile count: 2
// volatile count: 6
// volatile count: 7
// volatile count: 8
// volatile count: 9


private static void atomicCount() {
for (int i = 0; i < 10; i++) {
Executors.newFixedThreadPool(3).execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 通过使用Atomic包中的原子类保证数据操作是原子的(数据没有重复,表示是原子操作),但是不能保障有序性
System.out.println("atomic count: " + atomicCount.incrementAndGet());
}
});
}
}
// 打印结果:虽然顺序错乱,但是数据没有重复,也就说明保障了数据的操作是原子的,但是线程间不是有序的
// atomic count: 1
// atomic count: 2
// atomic count: 3
// atomic count: 5
// atomic count: 8
// atomic count: 9
// atomic count: 10
// atomic count: 4
// atomic count: 7
// atomic count: 6


private static void synchronizedCount() {
for (int i = 0; i < 10; i++) {
Executors.newFixedThreadPool(3).execute(new Runnable() {
@Override
public void run() {
synchronized (MyClass.class) { // 通过synchronized关键字来保证线程之间的有序性
System.out.println("synchronized count: " + ++synchronizedCount);
}
}
});
}
}
// 打印结果:没有重复数据,也没有错乱现象,说明数据操作是原子的,同时线程操作也是顺序的。同时也说明,有序性可以保障数据操作的原子性
// synchronized count: 1
// synchronized count: 2
// synchronized count: 3
// synchronized count: 4
// synchronized count: 5
// synchronized count: 6
// synchronized count: 7
// synchronized count: 8
// synchronized count: 9
// synchronized count: 10
}

参考:

0%