volatile
保证线程可见性
static boolean checkType = true;
public static void main(String[] args) throws Exception {
new Thread(()->{
while(checkType){
}
System.out.println("thread end");
}).start();
Thread.sleep(100);// 确保现场可以开始执行
checkType = false;//更改值 希望thread能够结束
/*
result: 线程一直执行 无法结束
原因是因为 线程之间变量是不可共享的
*/
}
static volatile boolean checkType = true;
public static void main(String[] args) throws Exception {
new Thread(()->{
while(checkType){
}
System.out.println("thread end");
}).start();
Thread.sleep(100);// 确保现场可以开始执行
checkType = false;//更改值 希望thread能够结束
/*
result: 线程可以结束
变量加上修饰符 volatile 可以让线程之间变量可见,所以变量值变化了 其它线程 是可以读到的
*/
}
禁止指令重排序
什么叫指令重排序?
编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。
也就是说,对于下面两条语句:
int a = 10;
int b = 20;
在计算机执行上面两句话的时候,有可能第二条语句会先于第一条语句执行;
编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。也就是说:在单线程环境下,指令执行的最终效果应当与其在顺序执行下的效果一致,否则这种优化便会失去意义。这句话有个专业术语叫做as-if-serial semantics (as-if-serial语义)
重排序对多线程的影响:在多线程程序中,对存在依赖重排序,可能会改变程序的执行结果。
private static int a,b,x,y;
private static int count=0;
public static void main(String[] args) throws Exception {
for(;;){
count++;
a=0; b=0;
x=0; y=0;
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
a=1;
x=b;
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
b=1;
y=a;
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
/*
代码分析,两个线程开始运行,无论是thread1 还是thread2先运行,a=1 或者 b=1先运行,x和y 必定有一个为1
thread1开始执行并走完, 那么 a=1,x=0;b=1,y=1; 0 1;
thread2开始执行并走完, 那么 b=1,y=0,a=1,x=1; 1 0;
thread1开始执行,a=1 thread2开始执行 b=1, 继续 x=b; y=a; 则 a=1,b=1,x=1,y=1; 1 1
绝无可能 x y 同时为0
*/
if(x==0 && y==0){
System.out.println(count+":"+x+","+y);
break;
}
/*
result: 117523:0,0
结论:有可能会出现这种情况x=0,y=0;
原因是指令重排序 导致thread1中的x=b; thred2中的y=a; 先执行完毕,才执行了a=1 b=1
*/
}
}