• Java并发(四)----线程运行原理


    1、线程运行原理

    1.1 栈与栈帧  

    Java Virtual Machine Stacks (Java 虚拟机栈 JVM)

    我们都知道 JVM 中由堆、栈、方法区所组成,其中栈内存是给谁用的呢?其实就是线程,每个线程启动后,虚拟机就会为其分配一块栈内存。

    • 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存

    • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

    单线程示例代码

    public class TestFrames {
        public static void main(String[] args) {
            method1(10); // 断点处
        }
    ​
        private static void method1(int x) {
            int y = x + 1;
            Object m = method2();
            System.out.println(m);
        }
    ​
        private static Object method2() {
            Object n = new Object();
            return n;
        }
    }

    在打断点处,可以看到一个栈帧

    执行到method1,可以看到新起了一个栈帧

    当执行到method2时,可以看到又新起了一个栈帧

    由于是栈,随着的程序的运行,后面开启的栈帧会先被销毁,直至main栈帧被销毁,此刻程序运行完成。

    对应图解:

    内存释放后

    具体就是:

    1.将编译好的字节码加载到jvm的方法区内存中
    2.jvm启动一个main的主线程,cpu核心就准备运行主线程的代码了,给主线程分配自己的栈内存【args、局部变量、返回地址、所记录】,每个线程的栈里面还有个程序计数器
    程序计数器的作用:当cpu要执行哪行代码了,就去这个里面去要
    3.把主方法的里面代码行放到程序计数器
    4.主方法调用的是method1的方法,为method1分配栈内存,里面存储这个方法里面局部变量,返回地址,这些变量是分配内存时,会把空间预留好
    5.将method1的第一行读到程序计数器让cpu执行
    6.methode1下一行调用method2()方法,创建他的栈内存
    7.把Object n = new Object()这行代码读取到计数器,在队中创建对象
    8.method2()将返回地址给m,方法执行完就可以释放掉method2()的栈内存
    9.一层层方法结束后,依次释放掉每个方法线程

    现在来看看多线程下的栈与栈帧

    public class TestFrames {
        public static void main(String[] args) {
            Thread t1 = new Thread(){
                @Override
                public void run() {
                    method1(20);// 断点处
                }
            };
            t1.setName("t1");
            t1.start();
            method1(10);// 断点处
        }
    ​
        private static void method1(int x) {
            int y = x + 1;
            Object m = method2();
            System.out.println(m);
        }
    ​
        private static Object method2() {
            Object n = new Object();
            return n;
        }
    }
    ​

    在第一个断点处

    可以看到多个线程同时运行中,我们可以选择具体的线程来查看运行状况并且往下运行,具体的读者可以自行实践。

    1.2 线程上下文切换(Thread Context Switch)

    因为以下一些原因导致 cpu 不再执行当前的线程,转而执行另一个线程的代码(简单来说就是从使用cpu到不使用cpu

    • 线程的 cpu 时间片用完

    • 垃圾回收

    • 有更高优先级的线程需要运行

    • 线程自己调用了 sleep、yield、wait、join、park、synchronized、lock 等方法

    当 Context Switch(上下文切换) 发生时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态,Java 中对应的概念就是程序计数器(Program Counter Register),它的作用是记住下一条 jvm 指令的执行地址,是线程私有的

    • 状态包括程序计数器、虚拟机栈中每个栈帧的信息,如局部变量、操作数栈、返回地址等

    • Context Switch 频繁发生会影响性能,因为线程数不是越多越好。

     



    如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    大工业用电计费及其相关知识
    5款提高工作效率的免费工具推荐
    无人机-地面站
    四种bean拷贝工具对比
    信号量与自旋锁的简单介绍
    canvas
    springboot 事务注解
    【Redis】SortedSet类型
    Flink中ExactlyOnce与AtleastOnce
    安卓开发Android studio学习笔记14:用户注册登录(案例演示)
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/16964644.html