其他
因为我说:volatile 是轻量级的 synchronized,面试官让我回去等通知!
The following article is from Java中文社群 Author 老王著
volatile 是并发编程的重要组成部分,也是面试常被问到的问题之一。不要向小强那样,因为一句:volatile 是轻量级的 synchronized,而与期望已久的大厂失之交臂。
内存可见性
// 可见性参数
private static boolean flag = false;
public static void main(String[] args) {
new Thread(() -> {
try {
// 暂停 0.5s 执行
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("flag 被修改成 true");
}).start();
// 一直循环检测 flag=true
while (true) {
if (flag) {
System.out.println("检测到 flag 变为 true");
break;
}
}
}
}
flag 被修改成 true
检测到 flag 变为 true
的结果,这是因为非主线程更改了 flag=true,但主线程一直不知道此值发生了改变,这就是内存不可见的问题。// 可见性参数
private static volatile boolean flag = false;
public static void main(String[] args) {
new Thread(() -> {
try {
// 暂停 0.5s 执行
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("flag 被修改成 true");
}).start();
// 一直循环检测 flag=true
while (true) {
if (flag) {
System.out.println("检测到 flag 变为 true");
break;
}
}
}
}
检测到 flag 变为 true flag 被修改成 true
指令重排
// 指令重排参数
private static int a = 0, b = 0;
private static int x = 0, y = 0;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
Thread t1 = new Thread(() -> {
// 有可能发生指令重排,先 x=b 再 a=1
a = 1;
x = b;
});
Thread t2 = new Thread(() -> {
// 有可能发生指令重排,先 y=a 再 b=1
b = 1;
y = a;
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("第 " + i + "次,x=" + x + " | y=" + y);
if (x == 0 && y == 0) {
// 发生了指令重排
break;
}
// 初始化变量
a = 0;
b = 0;
x = 0;
y = 0;
}
}
}
volatile 非同步方式
public static volatile int count = 0; // 计数器
public static final int size = 100000; // 循环测试次数
public static void main(String[] args) {
// ++ 方式
Thread thread = new Thread(() -> {
for (int i = 1; i <= size; i++) {
count++;
}
});
thread.start();
// -- 方式
for (int i = 1; i <= size; i++) {
count--;
}
// 等所有线程执行完成
while (thread.isAlive()) {}
System.out.println(count); // 打印结果
}
}
1065
public static int count = 0; // 计数器
public static final int size = 100000; // 循环测试次数
public static void main(String[] args) {
// ++ 方式
Thread thread = new Thread(() -> {
for (int i = 1; i <= size; i++) {
synchronized (VolatileExample.class) {
count++;
}
}
});
thread.start();
// -- 方式
for (int i = 1; i <= size; i++) {
synchronized (VolatileExample.class) {
count--;
}
}
// 等所有线程执行完成
while (thread.isAlive()) {}
System.out.println(count); // 打印结果
}
}
volatile 使用场景
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private transient volatile Object[] array;
final void setArray(Object[] a) {
array = a;
}
//...... 忽略其他代码
}
总结
有道无术,术可成;有术无道,止于术
欢迎大家关注Java之道公众号
好文章,我在看❤️