暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Java线程与内核线程

Netty历险记 2021-09-20
567

本篇文章探究下Java线程与内核线程的关系.
在Java中,一个Java的线程对应一个内核的线程,实际的业务代码是由内核线程来执行的,而Java线程只是一个傀儡.

先通过一个简单的实验热热身


    import java.lang.Thread;
    public class Example {
    public static void main(String[] args) throws Exception {
    new Thread(new Runnable() {
    @Override
    public void run() {
    try {
    Thread.sleep(20000);//休眠20秒
    } catch(Exception x) {}
    System.out.println("Thread-A");
    }
    }, "Thread-A").start();


    Thread.sleep(60000);
    System.out.println("main");
    }
    }


    以上代码,主要就是要让Thread-A线程先退出,然后JVM再退出. 

    观察下Thread-A线程退出之后,对应的内核线程是否也退出了.
    为了观察现象,使用到一个JDK自带的jvisualvm图形化工具和ps命令.



    编译并运行




    首先使用jvisualvm观察下线程的情况




    说明: 进程ID=686


    Thread-A线程在运行完成之后,就退出了,这里看到的线程是Java层面的线程,那么我们通过ps命令看下内核层面的线程情况.
    分别在Thread-A线程运行中和运行完成之后,通过ps -Lf 命令查看下线程.





    在Thread-A线程结束之后,对应的有个内核线程707也消失了,那么这个内核线程707是不是就是对应Java的Thread-A线程呢?   

    我们是使用strace -ff -o out java Example命令运行的程序,因此它会打印系统调用相关的信息.



    707内核线程打印了Thread-A, 也就是说,内核线程707对应Java的Thread-A线程.

    【总结】 当Java的线程退出之后,对应的内核线程也会退出.


    当然,以上是我们根据现象观察出来的结果,那么接下来我们通过查看JVM源码看一下.




    在Java中调用start方法启动线程, 底层映射到JVM中的JVM_StartThread方法.




    接下来继续调用创建逻辑.



    调用os::create_thread(this, thr_type, stack_sz)继续创建线程逻辑.



    底层调用C库的pthread_create创建内核线程

    创建完成之后, 子线程执行java_start方法,而父线程暂时阻塞住.




    子线程唤醒父线程,然后子线程阻塞住.

    父线程被唤醒之后,执行start方法.







    父线程唤醒之前阻塞的子线程



    子线程被唤醒之后,执行JVM中线程的run方法





    最后子线程会调用执行Java线程的run方法.  

    同时当Java线程的run方法执行完成之后, 线程就调用exit退出了.  这里也就解释了Java线程退出之后,内核线程也会退出的原因了.

    这里附一张全貌图





    总结一下就是父线程创建了子线程, 子线程执行完成之后,子线程就自动退出了.

    为了创建线程,对于我们JDK层面就是一个Thread类对象,但是其实JVM内部还涉及几个线程对象.比如JavaThread, OSThread





    包括你看到的JDK层面的Thread的线程状态,和JVM中的线程状态,以及内核的线程状态,都是不完全一样的.



    以上也只是分析了一个普通的线程退出之后,内核线程也自然退出了. 

    难道main线程也是这样的吗?   main线程是第一个线程吗?   

    我们后面再单独说下main线程的情况.


    文章转载自Netty历险记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论