目录
指令重排:
代码:
执行结果:
分析原因:
解决办法:
加入语句:
完整代码:
补充:
1.printStackTrace();
2.yield()
指令重排:
在class文件执行的时候,cpu为了提高执行的效率,可能会打乱代码编写的顺序,在多线程的情况下,指令重排可能会带来小概率的偶先错误
代码:
package com.iweb.test;
public class Test3 {
static Test3 test3;
static Boolean isInit;
static int count = 1;
public static void main(String[] args) {
while (true) {
isInit = false;
test3 = null;
//创建一个test3对象,用静态方法进行调用
Thread thread1 = new Thread(() -> {
test3 = new Test3();
isInit = true;
});
Thread thread2 = new Thread(() -> {
try {
if (isInit)
test3.doSomething();
} catch (Exception e) {
System.out.println("终于发生了指令重排");
e.printStackTrace();
System.exit(1);//跳出系统
}
});
thread1.start();
thread2.start();
}
}
public void doSomething() {
System.out.println("实验做到了" + count++ + "次");
}
}
执行结果:
分析原因:
可以看到在188次发生了指令重排 ,发生了空指针异常,没有创建test3对象时,即调用test3.doSomething,thread1或者thread2还没结束就开启下一次循环
解决办法:
主线程必须要等这次实验做完,才能开启循环去做下一次实验
加入语句:
如果thread1或者thread2还没结束:主线程让出cpu
while(thread1.isAlive()||thread2.isAlive()){
Thread.yield();
}
完整代码:
package com.iweb.test;
public class Test3 {
static Test3 test3;
static Boolean isInit;
static int count = 1;
public static void main(String[] args) {
while (true) {
isInit = false;
test3 = null;
Thread thread1 = new Thread(() -> {
test3 = new Test3();
isInit = true;
});
Thread thread2 = new Thread(() -> {
try {
if (isInit)
test3.doSomething();
} catch (Exception e) {
System.out.println("终于发生了指令重排");
e.printStackTrace();
System.exit(1);
}
});
thread1.start();
thread2.start();
while(thread1.isAlive()||thread2.isAlive()){
Thread.yield();
}
}
}
public void doSomething() {
System.out.println("实验做到了" + count++ + "次");
}
}
执行结果:在32w次左右发生了 thread1和thread2的顺序打乱
进一步解决:
在变量中加入volatile
static volatile Test3 test3;
static volatile Boolean isInit;
补充:
1.printStackTrace();
try{
//逻辑代码
}
catch(Exception e){
e.printStackTrace();
}
上述代码里的 e.printStackTrace()是什么意思呢?
当Java代码在运行过程中遇到异常时,代码运行会跳到catch代码快,捕获异常,实例化Exception类型的对象,e是该对象的名称,printStackTrace是该对象的一个方法,从printStackTrace的名称我们可以看到是用于打印某些东西,那么是打印什么东西呢?解释如下:
printStackTrace()方法的意思是:在命令行打印异常信息在程序中出错的位置及原因。
printStackTrace打印的是出现异常的详细信息,出错位置,对于指明错误原因有很大的帮助。
2.yield()
yield方法的功能
暂停当前正在执行的线程对象
并执行其他线程
注意事项
其他也包含当前线程