欢迎大家来到IT世界,在知识的湖畔探索吧!
难度
初级
学习时间
10分钟
适合人群
零基础
开发语言
Java
开发环境
- JDK v11
- IntelliJ IDEA v2018.3
友情提示
- 本教学属于系列教学,内容具有连贯性,本章使用到的内容之前教学中都有详细讲解。
- 本章内容针对零基础或基础较差的同学比较友好,可能对于有基础的同学来说很简单,希望大家可以根据自己的实际情况选择继续看完或等待看下一篇文章。谢谢大家的谅解!
1.温故知新
前面在《“全栈2019”Java多线程第五章:线程睡眠sleep()方法详解》一章中介绍了如何暂时停止执行线程。
在《“全栈2019”Java多线程第六章:中断线程interrupt()方法详解》一章中介绍了如何停止线程。
在《“全栈2019”Java多线程第七章:等待线程死亡join()方法详解》一章中介绍了如何让一个线程等待另一个线程执行完毕再执行。
在《“全栈2019”Java多线程第八章:放弃执行权yield()方法详解》一章中介绍了如何让一个线程放弃执行权。
在《“全栈2019”Java多线程第九章:判断线程是否存活isAlive()详解》一章中介绍了如何判断一个线程是否存活。
在《“全栈2019”Java多线程第十章:Thread.State线程状态详解》一章中介绍了线程的6种状态。
在《“全栈2019”Java多线程第十一章:线程优先级详解》一章中介绍了如何设置/获取线程的优先级。
在《“全栈2019”Java多线程第十二章:后台线程setDaemon()方法详解》一章中介绍了如何将一个线程设置为后台线程。
在《“全栈2019”Java多线程第十三章:线程组ThreadGroup详解》一章中介绍了线程组ThreadGroup。
现在我们来讲解线程与堆栈信息。
2.异常堆栈信息
我们之前在《“全栈2019”Java异常第十三章:访问异常堆栈跟踪信息》一章中接触过堆栈。这里就不再赘述,直接开始今天的内容。
先拿异常来演示一下堆栈信息。
演示:
请查看异常堆栈信息。
请观察程序代码及结果。
代码:
Main类:
结果:
从运行结果来看,发生异常的堆栈信息全部被打印在控制台上。
按照异常堆栈信息,我们来画一个图帮助大家理解。
首先是main()方法入栈:
然后,main()方法调用a()方法:
接着,a()方法调用b()方法:
最后,b()方法调用c()方法:
基本上异常堆栈信息就是如此。
有不理解上面图是什么意思的,请结合《“全栈2019”Java异常第十三章:访问异常堆栈跟踪信息》一章来看。
图看完了,程序代码也很简单,希望大家可以理解,下面的例子还有用到该示例。
3.线程堆栈信息
我们把上一小节的例子再改改,怎么改呢?
加入线程。例如:
运行程序,执行结果:
从运行结果来看,我们发现异常信息和之前的不一样了。对比之前的和现在的异常信息看看。
之前的异常信息:
java.lang.ArithmeticException: / by zero
at main.Main.c(Main.java:37)
at main.Main.b(Main.java:28)
at main.Main.a(Main.java:20)
at main.Main.main(Main.java:12)
现在的异常信息:
java.lang.ArithmeticException: / by zero
at main.Main.c(Main.java:43)
at main.Main$1.run(Main.java:32)
我们来把当前异常信息堆栈通过图文形式给大家画一下:
run()方法在栈底,c()方法在run()方法之上,和异常堆栈信息一致。
这个就很奇怪:main()方法、a()方法、b()方法哪去了?莫非前三个方法在一个栈,c()方法和run()方法在另一个栈?
是的,却是如此。main()方法、a()方法、b()方法在一个栈,c()方法和run()方法在另一个栈。
怎么来证明事实就是这样呢?
下面我们就只能通过获取线程堆栈信息来证明了。
4.获取当前线程的堆栈信息
获取线程的堆栈信息可以调用线程的getStackTrace()方法。
getStackTrace()方法在Thread类中的源码信息:
将注释翻译成中文:
去掉注释版:
getStackTrace()方法作用是返回线程的堆栈信息。
访问权限
public:getStackTrace()方法访问权限是公开的。
StackTraceElement[]:getStackTrace()方法返回此线程的堆栈信息数组,数组中每一个元素都是方法调用信息。
getStackTrace()方法只能被对象调用。
参数
无。
抛出的异常
无。
应用
我们就以获取当前线程的堆栈信息为例。
首先,我们来获取当前线程:
然后,我们调用线程的getStackTrace()方法来获取当前线程的堆栈信息数组:
接着,我们先来打印堆栈信息数组的长度:
最后,我们遍历该堆栈信息数组:
运行程序,执行结果:
从运行结果来看,程序没什么问题。下面来解释一下打印结果。
我们当前线程的堆栈信息数组中长度为2:
说明当前线程的堆栈信息数组中有两个方法调用链:
这个结果应该是从下往上看,第一个被调用的方法是main()方法:
第二个被调用的方法是Thread的getStackTrace()方法:
对应我们程序代码中的main()方法和getStackTrace()方法:
这下小伙伴们应该知道了getStackTrace()方法的基本用法。
接下来,我们对3小节示例通过getStackTrace()方法进行分析。
5.每一个线程都是一个新堆栈
对第3小节的例子,我们加入getStackTrace()方法后再来看看打印结果。
于是,改写Main类:
此次改写有两处。
第一处是我们在b()方法内部打印了当前线程堆栈信息数组长度和遍历了当前线程堆栈信息数组:
第二处是我们在c()方法内部同样打印了当前线程堆栈信息数组长度和遍历了当前线程堆栈信息数组:
现在我们来运行程序,看看执行结果:
运行结果要分两部分来看。
第一部分,也就是主线程的堆栈信息数组打印出来的结果:
第二部分,也就是我们新创建的线程它的堆栈信息数组打印出来的结果:
我们可以清楚地看到,主线程堆栈信息数组长度是4:
它里面存放了main()方法在内的4个方法调用链信息,其中有main()方法、a()方法、b()方法和getStackTrace()方法:
接着,我们来看新创建的线程,它的堆栈信息数组长度是3:
它里面存放了run()方法在内的3个方法调用链信息,其中有run()方法、c()方法和getStackTrace()方法:
如果我们c方法里面发生异常的话,结果会是怎样呢?
接下来,我们来改写Main类:
然后运行程序,看看执行结果:
从运行结果来看,只会打印c()方法及调用c()方法的run()方法。
为什么呢?
我们可以画画新线程的堆栈信息图:
从图中我们可以看到,run()方法、c()方法和getStackTrace()方法都在栈中。
因为我们在c()方法内部发生异常,所以要回溯的话,只能是从c()方法开始往回打印堆栈信息。
第3小节最后的问题,我们在这里也就解答了。
总结
- 每一个新线程都会有一个新的堆栈信息数组来存放方法调用信息。
- getStackTrace()方法作用是返回线程的堆栈信息。
至此,Java中线程堆栈信息相关内容讲解先告一段落,更多内容请持续关注。
答疑
如果大家有问题或想了解更多前沿技术,请在下方留言或评论,我会为大家解答。
上一章
“全栈2019”Java多线程第十三章:线程组ThreadGroup详解
下一章
“全栈2019”Java多线程第十五章:当后台线程遇到finally
学习小组
加入同步学习小组,共同交流与进步。
- 方式一:关注头条号Gorhaf,私信“Java学习小组”。
- 方式二:关注公众号Gorhaf,回复“Java学习小组”。
全栈工程师学习计划
关注我们,加入“全栈工程师学习计划”。
版权声明
原创不易,未经允许不得转载!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/36493.html