巧妙记住函数调用对应栈桢的出入栈

在学习JVM的时候,都会记住这样几个概念:

  • 栈是线程私有的。
  • 每个方法的调用对应着栈桢的入栈出栈。
  • 每个栈帧包含局部变量表、操作数栈以及指向当前方法所属类的运行时常量池的引用。
  • 局部变量是线程安全的

这些概念都不难理解也不难记住,不过吧总觉得这些就是干巴巴的概念,背下来也就过去了。今天突然意识到其实在看到这些相关概念前,就已经见到他们的身影并受到其恩惠了。

平时都有debug程序,而debug模式下可以看到调用栈信息,最开始学习debug的时候当时带我的同事就跟我说在Frames这里是debug调用栈,蓝色选中的就是当前程序停留的位置,它往下依次是调用的方法信息。右侧Variables就可以看到当前的变量信息。当时觉得很神奇但现在想想,调用栈里的每一层不对应着一个栈桢,然后variables中的值就是对应栈桢中存储的元素。

下面用一段死锁的demo来验证一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class DeadLock {
private static final Object o1 = new Object();
private static final Object o2 = new Object();
public static void main(String[] args) throws Exception{
ExecutorService threadPool = Executors.newFixedThreadPool(2);
threadPool.submit(new Runnable() {
@Override
public void run() {
int variableA = 10;
synchronized (o1){
System.out.println("thread:=="+Thread.currentThread()+"拿到o1资源");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2){
System.out.println("thread:=="+Thread.currentThread()+"拿到o2资源");
}
}
}
});
threadPool.submit(new Runnable() {
@Override
public void run() {
int variableA = 20;
synchronized (o2){
System.out.println("thread:=="+Thread.currentThread()+"拿到o2资源");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1){
System.out.println("thread:=="+Thread.currentThread()+"拿到o1资源");
}
}
}
});
threadPool.shutdown();
}
}

image-20191013171602272

image-20191013171640070


巧妙记住函数调用对应栈桢的出入栈
http://yuyangblog.cn/2019/10/13/巧妙记住函数调用对应栈桢的出入栈/
Aŭtoro
于洋
Postigita
October 13, 2019
Lizenta