您的位置 首页 java

“全栈2019”Java多线程第十四章:线程与堆栈信息详解

难度

初级

学习时间

10分钟

适合人群

零基础

开发语言

Java

开发环境

  • JDK v11
  • IntelliJ IDEA v2018.3

友情提示

  • 本教学属于系列教学,内容具有连贯性,本章使用到的内容之前教学中都有详细讲解。
  • 本章内容针对零基础或基础较差的同学比较友好,可能对于有基础的同学来说很简单,希望大家可以根据自己的实际情况选择继续看完或等待看下一篇文章。谢谢大家的谅解!

1.温故知新

前面在 一章中介绍了 如何暂时停止执行线程。

在 一章中介绍了 如何停止线程。

在 一章中介绍了 如何让一个线程等待另一个线程执行完毕再执行

在 一章中介绍了 如何让一个线程放弃执行权。

在 一章中介绍了 如何判断一个线程是否存活

在 一章中介绍了 线程的6种状态

在 一章中介绍了 如何设置/获取线程的优先级

在 一章中介绍了 如何将一个线程设置为后台线程

在 一章中介绍了 线程组ThreadGroup

现在我们来讲解 线程与堆栈信息

2.异常堆栈信息

我们之前在 一章中接触过堆栈。这里就不再赘述,直接开始今天的内容。

先拿异常来演示一下堆栈信息。

演示:

请查看异常堆栈信息。

请观察程序代码及结果。

代码:

Main类:

结果:

从运行结果来看,发生异常的堆栈信息全部被打印在控制台上。

按照异常堆栈信息,我们来画一个图帮助大家理解。

首先是main()方法入栈:

然后,main()方法调用a()方法:

接着,a()方法调用b()方法:

最后,b()方法调用c()方法:

基本上异常堆栈信息就是如此。

有不理解上面图是什么意思的,请结合 一章来看。

图看完了,程序代码也很简单,希望大家可以理解,下面的例子还有用到该示例。

3.线程堆栈信息

我们把上一小节的例子再改改,怎么改呢?

加入线程。例如:

运行程序,执行结果:

从运行结果来看,我们发现异常信息和之前的不一样了。对比之前的和现在的异常信息看看。

之前的异常信息:

现在的异常信息:

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多线程第十五章:当后台线程遇到finally

学习小组

加入同步学习小组,共同交流与进步。

  • 方式一:关注头条号Gorhaf,私信“Java学习小组”。
  • 方式二:关注公众号Gorhaf,回复“Java学习小组”。

全栈工程师学习计划

关注我们,加入“全栈工程师学习计划”。

版权声明

原创不易,未经允许不得转载!

文章来源:智云一二三科技

文章标题:“全栈2019”Java多线程第十四章:线程与堆栈信息详解

文章地址:https://www.zhihuclub.com/173443.shtml

关于作者: 智云科技

热门文章

网站地图