线程Thread基础及深入了解start启动线程过程

进程:指在一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程。进程也是程序的执行过程,是系统运行程序的基本单位。系统运行一个程序就是一个进程从创建到运行到死亡的过程。

线程:进程内部的一个独立执行单元;一个进程可以并发运行多个线程。

 

进程与线程的区别:

进程:有独立的内存空间,进程中的数据存放空间(堆空间栈空间是独立的),至少包含一个线程

线程:堆空间共享,栈空间是独立的,线程消耗的资源比进程小得多

 

注意:

因为一个进程中多个线程是并发运行的,那么从微观角度看也是有先后顺序的,那个线程先调用完全取决于CPU的调度,程序员是干涉不了的,这也是多线程随机的原因

 

多线程的优势:

  1. 进程之间不能共享内存,而线程之间可以共享内存(堆)

  2. 系统创建进程需要为该进程重新分配系统资源,创建线程则代价小得多

  3. Java本身内置多线程功能的支持

 

线程的创建方式:

1.继承Thread类重写run方法

2.实现Runnable接口实现run方法    调用时Thread t = new Thread(new 新类())

3.使用匿名内部类创建线程

Thread t = new Thread(){
    @Override
    public void run() {
        System.out.println("xxx");
    }
};

4.使用Lambda简化匿名内部类的写法

Thread t = new Thread(() -> System.out.println("xxx"));

启动线程是start不是run

原因:

Run方法:在本地线程内调用run方法,和其他方法调用没区别,可以重复多次调用

Statr方法:启动一个线程,实际上还是调用这个run方法

 

从源码分析为什么使用start开启线程

可以看到start方法中调用了start0方法,而start0方法并没有具体的方法体,而有native关键字修饰,简单来讲native method就是一个java调用非java的接口,即该方法的实现由非java语言实现。

而在Thread类的开头我们可以看到

有个本地静态方法registerNatives,而在静态块中调用了这个方法,相当于当这个类加载到JVM的时候它就会被调用,进而注册相应的本地方法

查看OpenJDK的源码

http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/00cd9dc3c2b5/src/share/native/java/lang/Thread.c

可以看到最后调用了JVM_StartThread方法,通过名字大概可以猜测是JVM启动线程的一个方法

在 jvm.cpp 中,有如下代码段:

1

2

3

4

5

6

7

8

9

static void thread_entry(JavaThread* thread, TRAPS) {

   HandleMark hm(THREAD);

    Handle obj(THREAD, thread->threadObj());

    JavaValue result(T_VOID);

    JavaCalls::call_virtual(&result,obj,

    KlassHandle(THREAD,SystemDictionary::Thread_klass()),

    vmSymbolHandles::run_method_name(),

vmSymbolHandles::void_method_signature(),THREAD);

}

 

 

这里JVM_ENTRY是一个宏,用来定义JVM_StartThread 函数,可以看到函数内创建了真正的平台相关的本地线程,其线程函数是 thread_entry

 

1

2

3

4

5

6

7

8

9

static void thread_entry(JavaThread* thread, TRAPS) {

   HandleMark hm(THREAD);

    Handle obj(THREAD, thread->threadObj());

    JavaValue result(T_VOID);

    JavaCalls::call_virtual(&result,obj,

    KlassHandle(THREAD,SystemDictionary::Thread_klass()),

    vmSymbolHandles::run_method_name(),

vmSymbolHandles::void_method_signature(),THREAD);

}

 

 

可以看到调用了 vmSymbolHandles::run_method_name 方法,这是在 vmSymbols.hpp 用宏定义的:

1

2

3

4

5

class vmSymbolHandles: AllStatic {

   

    template(run_method_name,"run")

   

}

 

 

至于 run_method_name 是如何声明定义的,因为涉及到很繁琐的代码细节,本文不做赘述。感兴趣的读者可以自行查看 JVM 的源代码

Java 线程创建调用关系图

综上所述,Java 线程的创建调用过程如 图 1 所示,首先 , Java 线程的 start 方法会创建一个本地线程(通过调用 JVM_StartThread),该线程的线程函数是定义在 jvm.cpp 中的 thread_entry,由其再进一步调用 run 方法。可以看到 Java 线程的 run 方法和普通方法其实没有本质区别,直接调用 run 方法不会报错,但是却是在当前线程执行,而不会创建一个新的线程

 

参考文档:

https://www.ibm.com/developerworks/cn/java/j-lo-processthread/#icomments

https://www.linuxidc.com/Linux/2016-03/128997.htm

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值