0%

java | 可见性

  • 可见性
    • 保证指令不会受到 CPU 缓存的影响

可见性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.redisc;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.Run")
public class Run {

static boolean run = true;

public static void main(String[] args) throws Exception {
new Thread(() -> {
while (run) {

}
}).start();

Thread.sleep(1000);
run = false;
}

}

这段代码在运行的时候,并不会跳出循环。

最开始的时候,t 线程从主内存中读取 run 的值,由于多时间内多次读取,所以 JIT 编译器,会将 run 值缓存到自己的工作内存中的高速缓存中,减少对主存中的 run 的访问,即便是,后来 run 的值被改变了,但是,还是从缓存中读取。「ps:不过,这个说法貌似有点不对,以后查证后我再完善。」

可见性解决 volatile

被 volatile 修饰的变量,不能从高速缓存中读取值。

可以修饰

  • 成员变量
  • 静态成员变量
1
volatile static boolean run = true;

使用 synchronized 解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.redisc;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.Run")
public class Run {

static boolean run = true;

public static void main(String[] args) throws Exception {
new Thread(() -> {
while (true) {
if (!run) {
break;
}
}
}).start();

Thread.sleep(1000);
run = false;
}

}

使用 synchronized

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
package com.redisc;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.Run")
public class Run {

static boolean run = true;
final static Object lock = new Object();

public static void main(String[] args) throws Exception {
new Thread(() -> {
while (true) {
synchronized (lock) {
if (!run) {
break;
}
}
}
}).start();

Thread.sleep(1000);
synchronized (lock) {
run = false;
}
}

}

这是因为 synchronized 每次加锁前都会清除工作内存,然后重新在主内存中拷贝最新的变量副本到工作内存,执行代码,将修改后的共享变量值刷新到主内存中,释放锁。

请我喝杯咖啡吧~