Spa*_*ara 8 java debugging multithreading breakpoints
我对这段代码有一个奇怪的问题:
class Test {
private static boolean test = false;
public static void main(String[] args) {
new Thread(() -> {
while (true) {
if (test) {
System.out.println("Print when breakpoint here!");
test = false;
}
}
}, "Thread1").start();
new Thread(() -> {
while (true) {
System.out.println("Print always");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
test = true;
}
}, " Thread2").start();
}
}
Run Code Online (Sandbox Code Playgroud)
正如我所料,因为boolean test
不是volatile
,Thread1使用本地缓存值,test
当Thread2将其更改为Thread1时,true
它将不会执行任何操作.但是当我在线上放置一个断点时 System.out.println("Prints when put a breakpoint here!");
它将到达那里并打印出线!通过设置断点真正发生了什么?它是否强制程序直接从内存中读取变量的值?或者其他事情正在发生?
正如我所料,由于布尔测试不是易失性,因此Thread1使用测试的本地缓存值,当Thread2将其更改为true时,Thread1将不会执行任何操作.
你的期望是不正确的.
根据Java语言规范,如果一个线程更新非易失性共享变量,而另一个线程随后在没有适当同步的情况下读取它,则第二个线程可能会看到新值,或者它可能会看到更早的值.
所以你看到的是JLS允许的.
实际上,当调试代理附加到JVM时,它通常会在较低的优化级别JIT编译方法......或者使用字节码解释器执行它们.对于在其中设置断点的方法以及单步执行1时,可能会发生这种情况.对于使用共享变量但在调试时没有正确同步的代码,这可能会导致不同的行为.
这是由于同步不充分导致调试问题困难的原因之一.
据我所知,断点通过添加一个名为INT 3的特殊陷阱来改变代码指令.那么究竟发生了什么呢?
这就是调试C/C++时会发生的情况.没有指定JVM如何处理这个问题,但是典型的JVM还有其他实现断点的选项...因为字节码和JIT编译.
当我
sleep(1)
在Thread1
before if语句中放入一个它也将打印该行.通过添加睡眠是否会发生同样的事情?
这sleep
将导致当前线程被挂起.未指定在实现级别发生的情况.然而,这是有可能的是,本地线程机制将刷新为挂起的线程对存储器...任何未完成的写操作(即,脏的高速缓存条目)作为执行线程上下文切换的过程的一部分.
类似地,如果使用print语句,典型的I/O堆栈具有可以触发缓存刷新等的内部同步.这也可以改变您尝试调试的代码的行为.
但是,我应该强调这些行为没有具体说明.
1 - 允许JIT优化器重新排序分配,前提是这不会改变单线程行为.但是,如果您正在调试方法并观察变量值,则重新排序的效果是可见的(对程序员而言).去优化/解释避免了这种情况.幸运的是,现代JVM /调试代理可以根据需要"即时"执行此操作.
归档时间: |
|
查看次数: |
319 次 |
最近记录: |