让变量可见,但是如果使用sout()同样会影响变量的可见性
不加valatile关键字
@Data
@Slf4j
public class Student {
public static int init = 0;
public static int max = 5;
@SneakyThrows
public static void main(String[] args) {
new Thread(() -> {
int local = init;
while (local < max) {
if (local != init) {
System.out.println("观察线程,local变量的值----"+local);
System.out.println("观察线程,init变量的值----"+init);
}
}
}).start();
new Thread(() -> {
int local = init;
do {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
init = ++local;
System.out.println("更新线程,输出init值:" + init);
} while (local < max);
}).start();
}
}
更新线程,输出init值:1
更新线程,输出init值:2
更新线程,输出init值:3
更新线程,输出init值:4
更新线程,输出init值:5
加volatile关键字
@Data
@Slf4j
public class Student {
public static volatile int init = 0;
public static int max = 5;
@SneakyThrows
public static void main(String[] args) {
new Thread(() -> {
int local = init;
while (local < max) {
if (local != init) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("观察线程,init值改变,init变量的值----"+init);
}
}
}).start();
new Thread(() -> {
int local = init;
do {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
init = ++local;
System.out.println("更新线程,输出init值:" + init);
} while (local < max);
}).start();
}
}
更新线程,输出init值:1
观察线程,init值改变,init变量的值----1
更新线程,输出init值:2
观察线程,init值改变,init变量的值----2
更新线程,输出init值:3
观察线程,init值改变,init变量的值----3
更新线程,输出init值:4
观察线程,init值改变,init变量的值----4
更新线程,输出init值:5
观察线程,init值改变,init变量的值----5
不加volatile关键字,但是有sout()
@Data
@Slf4j
public class Student {
public static int init = 0;
public static int max = 5;
@SneakyThrows
public static void main(String[] args) {
new Thread(() -> {
int local = init;
// 死循环
while (local < max) {
// 关键的一行
System.out.println("输出init值" + init);
// 测试init变量是否可见,不相等代表感知到init值的改变
if (local != init) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("观察线程,init值改变,init变量的值----"+init);
}
}
}).start();
new Thread(() -> {
int local = init;
do {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
init = ++local;
System.out.println("更新线程,输出init值:" + init);
} while (local < max);
}).start();
}
}
// 输出内容也能看到类似的内容,表明变量init变化,观察线程还是感知到了
更新线程,输出init值:1
观察线程,init值改变,init变量的值----1
更新线程,输出init值:2
观察线程,init值改变,init变量的值----2
观察线程,init值改变,init变量的值----2
更新线程,输出init值:3
观察线程,init值改变,init变量的值----3
更新线程,输出init值:4
观察线程,init值改变,init变量的值----4
原因, println 有一个上锁的操作。使用了 synchronized 上锁会做以下操作