java栈是线程安全的吗(Java多线程第十四章)

难度

初级

学习时间

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多线程第十一章:线程优先级详解》一章中介绍了如何设置/获取线程的优先级

结果:

java栈是线程安全的吗(Java多线程第十四章)(1)

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

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

首先是main()方法入栈:

java栈是线程安全的吗(Java多线程第十四章)(2)

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

java栈是线程安全的吗(Java多线程第十四章)(3)

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

java栈是线程安全的吗(Java多线程第十四章)(4)

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

java栈是线程安全的吗(Java多线程第十四章)(5)

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

有不理解上面图是什么意思的,请结合《“全栈2019”Java异常第十三章:访问异常堆栈跟踪信息》一章来看。

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

3.线程堆栈信息

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

加入线程。例如:

java栈是线程安全的吗(Java多线程第十四章)(6)

运行程序,执行结果:

java栈是线程安全的吗(Java多线程第十四章)(7)

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

之前的异常信息:

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)

我们来把当前异常信息堆栈通过图文形式给大家画一下:

java栈是线程安全的吗(Java多线程第十四章)(8)

run()方法在栈底,c()方法在run()方法之上,和异常堆栈信息一致。

这个就很奇怪:main()方法、a()方法、b()方法哪去了?莫非前三个方法在一个栈,c()方法和run()方法在另一个栈?

是的,却是如此。main()方法、a()方法、b()方法在一个栈,c()方法和run()方法在另一个栈。

怎么来证明事实就是这样呢?

下面我们就只能通过获取线程堆栈信息来证明了。

4.获取当前线程的堆栈信息

获取线程的堆栈信息可以调用线程的getStackTrace()方法。

getStackTrace()方法在Thread类中的源码信息:

java栈是线程安全的吗(Java多线程第十四章)(9)

将注释翻译成中文:

java栈是线程安全的吗(Java多线程第十四章)(10)

去掉注释版:

java栈是线程安全的吗(Java多线程第十四章)(11)

getStackTrace()方法作用是返回线程的堆栈信息。

访问权限

public:getStackTrace()方法访问权限是公开的。

StackTraceElement[]:getStackTrace()方法返回此线程的堆栈信息数组,数组中每一个元素都是方法调用信息。

getStackTrace()方法只能被对象调用。

参数

无。

抛出的异常

无。

应用

我们就以获取当前线程的堆栈信息为例。

首先,我们来获取当前线程:

java栈是线程安全的吗(Java多线程第十四章)(12)

然后,我们调用线程的getStackTrace()方法来获取当前线程的堆栈信息数组:

java栈是线程安全的吗(Java多线程第十四章)(13)

接着,我们先来打印堆栈信息数组的长度:

java栈是线程安全的吗(Java多线程第十四章)(14)

最后,我们遍历该堆栈信息数组:

java栈是线程安全的吗(Java多线程第十四章)(15)

运行程序,执行结果:

java栈是线程安全的吗(Java多线程第十四章)(16)

从运行结果来看,程序没什么问题。下面来解释一下打印结果。

我们当前线程的堆栈信息数组中长度为2:

java栈是线程安全的吗(Java多线程第十四章)(17)

说明当前线程的堆栈信息数组中有两个方法调用链:

java栈是线程安全的吗(Java多线程第十四章)(18)

这个结果应该是从下往上看,第一个被调用的方法是main()方法:

java栈是线程安全的吗(Java多线程第十四章)(19)

第二个被调用的方法是Thread的getStackTrace()方法:

java栈是线程安全的吗(Java多线程第十四章)(20)

对应我们程序代码中的main()方法和getStackTrace()方法:

java栈是线程安全的吗(Java多线程第十四章)(21)

这下小伙伴们应该知道了getStackTrace()方法的基本用法。

接下来,我们对3小节示例通过getStackTrace()方法进行分析。

5.每一个线程都是一个新堆栈

对第3小节的例子,我们加入getStackTrace()方法后再来看看打印结果。

于是,改写Main类:

java栈是线程安全的吗(Java多线程第十四章)(22)

此次改写有两处。

第一处是我们在b()方法内部打印了当前线程堆栈信息数组长度和遍历了当前线程堆栈信息数组:

java栈是线程安全的吗(Java多线程第十四章)(23)

第二处是我们在c()方法内部同样打印了当前线程堆栈信息数组长度和遍历了当前线程堆栈信息数组:

java栈是线程安全的吗(Java多线程第十四章)(24)

现在我们来运行程序,看看执行结果:

java栈是线程安全的吗(Java多线程第十四章)(25)

运行结果要分两部分来看。

第一部分,也就是主线程的堆栈信息数组打印出来的结果:

java栈是线程安全的吗(Java多线程第十四章)(26)

第二部分,也就是我们新创建的线程它的堆栈信息数组打印出来的结果:

java栈是线程安全的吗(Java多线程第十四章)(27)

我们可以清楚地看到,主线程堆栈信息数组长度是4:

java栈是线程安全的吗(Java多线程第十四章)(28)

它里面存放了main()方法在内的4个方法调用链信息,其中有main()方法、a()方法、b()方法和getStackTrace()方法:

java栈是线程安全的吗(Java多线程第十四章)(29)

接着,我们来看新创建的线程,它的堆栈信息数组长度是3:

java栈是线程安全的吗(Java多线程第十四章)(30)

它里面存放了run()方法在内的3个方法调用链信息,其中有run()方法、c()方法和getStackTrace()方法:

java栈是线程安全的吗(Java多线程第十四章)(31)

如果我们c方法里面发生异常的话,结果会是怎样呢?

接下来,我们来改写Main类:

java栈是线程安全的吗(Java多线程第十四章)(32)

然后运行程序,看看执行结果:

java栈是线程安全的吗(Java多线程第十四章)(33)

从运行结果来看,只会打印c()方法及调用c()方法的run()方法。

为什么呢?

我们可以画画新线程的堆栈信息图:

java栈是线程安全的吗(Java多线程第十四章)(34)

从图中我们可以看到,run()方法、c()方法和getStackTrace()方法都在栈中。

因为我们在c()方法内部发生异常,所以要回溯的话,只能是从c()方法开始往回打印堆栈信息。

第3小节最后的问题,我们在这里也就解答了。

总结
  • 每一个新线程都会有一个新的堆栈信息数组来存放方法调用信息。
  • getStackTrace()方法作用是返回线程的堆栈信息。

至此,Java中线程堆栈信息相关内容讲解先告一段落,更多内容请持续关注。

答疑

如果大家有问题或想了解更多前沿技术,请在下方留言或评论,我会为大家解答。

上一章

“全栈2019”Java多线程第十三章:线程组ThreadGroup详解

下一章

“全栈2019”Java多线程第十五章:当后台线程遇到finally

学习小组

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

  • 方式一:关注头条号Gorhaf,私信“Java学习小组”。
  • 方式二:关注公众号Gorhaf,回复“Java学习小组”。
全栈工程师学习计划

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

java栈是线程安全的吗(Java多线程第十四章)(35)

版权声明

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

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页