线程运行原理

栈与栈帧

JVM由堆、栈、方法区组成。其中栈就是给线程用的。每个线程启动后,虚拟机就会为其分配一块栈内存。

  • 每个栈由多个栈帧组成。栈帧是每次方法调用时所占用的内存。
  • 每个线程只能有一个活动栈帧,对应当前正执行的方法

单线程(main线程)例子

image.png

package com.zqh.day1;

/**
 * 一个线程(main)的栈与栈帧
 * 创建了三个栈帧,因为有三个方法
 */
public class Frames {
    public static void main(String[] args) {
        method1(1);
    }
    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,method1输出method2。
main是一个主线程,主线程已启动,虚拟机就会给他分配一块栈内存。栈内存由一个个栈帧组成,先调用的是main方法,就会为main方法产生一个栈帧,
image.png,里面是方法的参数image.png
主方法又会调用method1,JVM又会为method1产生一个栈帧
image.png,而method1又会调用method2,就会又产生一个栈帧
image.png栈是后进先出的。method2最后进入的,然而执行完却是第一个走的。

图解栈帧(main线程)

当执行这个类的时候,首先是类加载(把类里的方法放在方法区)image.png
加载完,虚拟机就会启动一个main线程,为他分配内存,接下来线程交给任务调度器进行执行,main线程里又会有一个main方法的栈帧内存image.png局部变量里就是局部变量和方法参数,像main方法,JVM会生成一个String数组,然后args会指向它
image.pngmain方法的返回地址是程序的退出地址。

然后走到method1,JVM会给method1分配一个栈帧,如图image.png它的返回地址是image.png

走到method2的时候,又分配一个栈帧。
完整执行流程
image.png
然后执行完依次返回,结束程序

两个线程的栈与栈帧

主线程已经写好了,添加一个线程

package com.zqh.day1;

public class ThreadsFrames {
    // 创建一个主线程
    public static void main(String[] args) {
        // 创建一个t1线程
        Thread t1 = new Thread(){
            // t1线程执行method1时参数为20
            @Override
            public void run() {
                method1(20);
            }
        };
        t1.setName("t1");
        t1.start();
        // 主线程执行method1参数为10
        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;
    }
}

在主线程和t1线程调用method1时都打个断点,断点模式选Thread
image.pngdebug
先创建了main线程,和main方法的栈帧
image.png
下拉列表还有个t1线程image.png。这俩可以分开走。
先看主线程。
image.png进method1了,再走就是method2。
看t1线程,走到method1image.png
证明主线程和t1线程之间的栈帧是相互独立的

小结

一个线程对应一个栈。栈由栈帧组成,一个方法对应一个栈帧,每个线程的栈帧是相互独立的

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

一个线程把CPU分配的时间片用完了**(并不是线程执行完了),就要把CPU使用权交给其他线程,从使用CPU到不使用CPU,就是一次上下文切换。
发生上下文切换的原因:
image.png
第一个不用解释了,第二个垃圾回收,垃圾回收的时候会暂停所有线程,让垃圾回收的线程进行垃圾回收。就发生上下文切换。前三种都是被动
第四种:线程自己调用了一些暂停的方法。
当上下文切换发生的时候,需要
保存当前线程的状态**。
比如一个线程要执行十行代码,但是当执行完八行代码的时候,CPU时间片用完了,就记录一下“现在执行到了第八行代码”,然后再上下文切换,恢复另一个线程的状态。
Java中由程序计数器来干这个事,当要发生上下文切换的时候,程序计数器就把当前线程下条JVM指令的执行地址记住,用于后面恢复。记录的还包括这些信息
image.png
上下文切换太频繁,会影响性能。
所以,线程数不是越多越好,(因为上下文切换太频繁)
image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值