java源码解析之thread(一)

    又一周过去,先来交代一下最近发生的事情:

        本周有只上了两天课,周三相当于没课。 周四周五加周末两天放假,因为学校弄运动会。  时间安排上,周三相当于浪费,状态不行,时间太零碎。   周四周五算慢慢地前行。  但是周五下午以及晚上状态不是很好,心情出了点问题,有点消极。  由此引发的是:周六学习了半天,娱乐了半天,晚上狂看电影。   总体来看,不是很满意,但是勉强能接受。

        由上上周的历史遗留问题,就是发现自己基础弄得太多,却导致自己的实例练习滞后了,中途也碰到了各种让自己怠慢的理由。  因此本周反思了好一段时间,也自责了好一段时间。  所幸的是尽管自己主观情绪上懈怠了,但是根据原来的学习惯性还没有太过浪费这个假期。 

    接着是学习总结:

        按计划,本周查看的Thread源码。  老规矩,先上图:

《java源码解析之thread(一)》

    这张图比之前看过的所有的体系都要少,问题在于一方面,这个涉及到更多与VM的交互,所以很多的实现要么直接交给jvm调用了,要么就交给c处理了,所以没有太多的花样。  另一方面,虽然源码少了,但是理解起来却不轻松。 可能是近半月来的长期查看源码吧,导致有些疲倦,脑子也不够灵活。   进下来,继续按照自己查看源码的时间线进行解说:

    Thread,我们经常看到他的时候大多是在多线程编程的时候,事实上,从操作系统方面来说,我们知道一个应用,不论他是人机交互的具有ui的界面,还是黑底白字冷冰冰的cmd命令行,还是隐藏在任务管理器中的一个占位符,它都是一个进程。  在上计算机导论课的时候,我们应该也听说了,进程由线程组成。  我想这应该算是我们第一次接触线程,而非在学习多线程编程的时候第一次接触。  不记得在哪本书看过,进程是计算机科学领域应用最成功的技术之一。  进程之间的相互切换,构成了我们看到的丰富多彩的计算机系统中的内容。 发现自己又跑题了,生硬的拉回一波。   嗯   咳咳~~,今天介绍的是 线程,Thread,看看它的源码吧:

    《java源码解析之thread(一)》

     上图为它的引用关系: 大致了解到它需要用到基础包:ref中的引用,concurrent包中的线程安全相关的工具类,sun包中的反射类。(注意不是reflect包哦)  嗯嗯,了解。

    接下来看看官方的权威解释:

《java源码解析之thread(一)》

    上图说明了一个线程的一些基本属性,它被建立后,权重默认跟其父类一样。  线程分为守护线程与非守护线程,当所有守护线程运行完毕后,程序就停止啦,也就是这个线程就完了。 守护线程建立的线程也为守护线程。  通常我们看到的main线程被称为主线程,程序运行的就是它里面的内容,那么它自然是一个非守护线程了。 需要注意,它跟普通的线程有一点特殊,但又不是本质上的区别,下文回涉及。继续:

《java源码解析之thread(一)》

《java源码解析之thread(一)》

《java源码解析之thread(一)》

 

    上3张图为它的属性分布,可以看到,它这里面有几个比较主要的依赖,类加载器,线程组,Runnable接口,守护线程的标志位,权重,线程Id,线程状态。需要注意的有:  这里面有一个 stackSize,这个相信我们都比较属性,中文意思也很容易得到,即栈大小。同时,注意到它里面有好些个属性都是VM直接维护的。   另外,有一个ThreadLocal类,记录了本地(相对于VM)的一些信息。 可以进去看看:

《java源码解析之thread(一)》

《java源码解析之thread(一)》

    通过大致的浏览类介绍,可以粗略的知道,它回为没有线程保存一个本地的副本,当线程结束后,回被垃圾收集机制给处理了。   包私有,用键的弱引用维持map,哈希自适应,维持本地线程的值。 看了有一段时间了,越看越蒙哈哈。  回过头去:

《java源码解析之thread(一)》

    上图中记录了几个常量值,都是与线程权重相关的。 即 默认权重,最小权重,最大权重。  另外一个重要的方法,即声明为native的那个currentThread()。  可以知道在java中判断当前线程并不是自己处理,而是交给jvm判断当前线程。  很多方法都会用到它。 继续:

《java源码解析之thread(一)》

    线程调度的。  跟着有道大致翻译了下,认为比较重要的就是: 防止过度占用CPU. 同时注意其为native方法。 

《java源码解析之thread(一)》

    这个算是线程中比较重要的方法了。 因为我们使用的线程的目的也在于此。 可以看到这个方法在进行线程状态判断时候,对于主线程 以及 系统线程组中的线程进行了过滤。   这也是为什么上文说主线程有点特殊。 据说,主线程也可以不叫main的,只不过需要我们去修改引导程序好像。  同时将它方法的下半部分给出:

《java源码解析之thread(一)》

    可以看到,线程启动的实际方法为start0(),其为native方法。  注意到 start()方法做了很多的状态维护,状态更新,信息维护,环境检查等工作。 这里需要注意一下,start方法的顶部注释部分: 让这个线程开始执行的方法,jvm调用这个线程的run方法。 事实上,这个run方法就是线程要执行的代码,其通过覆盖runnable接口的run方法实现。   这时至少有两个线程正在运行,一个是调用的线程的线程,另一个是被调用的线程。  一个线程不能在启动状态的同时又被启动。   继续: 

《java源码解析之thread(一)》

    这个是线程的退出的方法。 查看它的官方权威说明: 这个方法被系统调用,使得线程在真正退出之前有机会清理(维护本地状态)。  可以看到,它做了这些事情:将本线程统辖的线程组初始化为空,(在此之前应该回停掉线程组中的线程);将tartet也就是要执行的目标代码块初始化为空;将记录的本地线程初始化为空,以及初始化空一些其它的属性。 至于这里为什么要初始化,我想是为了减少内存消耗吧。实在想不出其它的什么理由,请原谅小白。继续:

《java源码解析之thread(一)》

    线程的中断,可以看到也是native的,同时是线程安全的。 

《java源码解析之thread(一)》

    线程安全的方法,负责多线程间的交互的,以前练习的时候用过,但是具体啥用搞忘了。 看它的注释好像是说: 设置线程的超时时间。 有时间了仔细练习下在解决这个疑惑。 

《java源码解析之thread(一)》

    设置创建的线程为守护线程的方法。  注意官方权威解释部分:  这个方法必须在 线程被执行前调用。

《java源码解析之thread(一)》

    线程的toString方法,优点意思。 我发现很多类的toString方法都挺有意思的。  前提是它要覆盖Object方法哈!。 

《java源码解析之thread(一)》

    可以看到上文中,Thread方法中有个属性记录了栈大小。 这个方法有点牛皮了。 它记录了栈中的信息,我们平时经常看到的那一大串打哪来吖?  就这!! 看看,StactTrace,栈帧信息。  嘿嘿。 了解到,每个线程都有自己的栈帧信息,所有的栈帧信息被一个StackTraceElement的二维数组存储起来了。  该二维数组中第一维记录线程,第二维记录当前线程的栈帧信息。 

    另外具有简易说明的版本:

《java源码解析之thread(一)》

    看看进度条,发现内容已不少,遂新开一篇吧。 

    原文作者:java源码分析
    原文地址: https://blog.csdn.net/qq_36285943/article/details/80039485
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞