计算机线程
- 现代操作系统在运行一个程序时,会为其创建一个进程。例如,启动一个Java程序,操作系统就会创建一个Java进程。进程由进程控制块、程序块、数据块和堆栈组成。
- 线程是系统独立调度和 CPU 分配的最小单位,它是进程中的一个实体,除拥有运行中必不可少的资源(程序计数器、寄存器和栈等)外,不拥有其他系统资源,故而又称轻量级进程。尽管线程不拥有系统资源,但它可与同属一个进程的其他线程一起共享该进程所拥有的全部资源。
-
用户级线程(User-Level Thread)
指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。另外,用户线程是由应用进程利用线程库创建和管理,不依赖于操作系统核心。不需要用户态/核心态切换,速度快。同一进程中只能同时有一个用户线程在运行,因此一个线程阻塞将使得整个进程(包括它的所有线程)阻塞。由于这里的处理器时间片分配是以进程为基本单位,所以每个线程执行的时间相对减少。
-
内核级线程(Kernel-Level Thread)
线程的所有管理操作都是由操作系统内核完成的。内核保存线程的状态和上下文信息,当一个线程执行了引起阻塞的系统调用时,内核可以调度该进程的其他线程执行。在多处理器系统上,内核可以分派属于同一进程的多个线程在多个处理器上运行,提高进程执行的并行度。由于需要内核完成线程的创建、调度和管理,所以和用户级线程相比这些操作要慢得多,但是仍然比进程的创建和管理操作要快。大多数市场上的操作系统,如Windows,Linux等都支持内核级线程。
用户级线程&内核级线程.png
计算机线程上下文切换:
一个进程只能运行在用户方式(usermode)或内核方式(kernelmode)下。用户程序运行在用户方式下,而系统调用运行在内核方式下。在这两种方式下所用的堆栈不一样:用户方式下用的是一般的堆栈,而内核方式下用的是固定大小的堆栈(一般为一个内存页的大小)当一个进程从用户空间进入内核空间时,它就不再有自己的进程空间了。这也就是为什么我们经常说线程上下文切换会涉及到用户态到内核态的切换原因所在。
JMM模型
Java线程与系统内核线程关系
- 示例图
Java线程与系统内核线程关系.png
Java1.2之前创建的线程为用户级线程,程序员们为JVM开发了自己的一个线程调度内核,而到操作系统层面就是用户空间内的线程实现;1.2及以后,JVM选择了更加稳健且方便使用的操作系统原生的线程模型,通过系统调用,将程序的线程交给了操作系统内核进行调度。
也就是说,现在的Java中线程的本质,其实就是操作系统中的线程,Linux下是基于pthread库实现的轻量级进程,Windows下是原生的系统Win32 API提供系统调用从而实现多线程。
Java线程
线程的五种状态
线程的五种状态.png
- JVM运行程序的实体是线程,每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),用于存储线程私有的数据,线程与主内存中的变量操作必须通过工作内存间接完成,主要过程是将变量从主内存拷贝到每个线程各自的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存。
- Java线程的上下文切换:CPU通过给每个线程分配CPU时间片来实现;时间片是CPU分配给各个线程的时间,因为时间片非常短,所CPU通过不停地切换线程执行,让我们感觉多个线程是同时执行的,CPU将当前任务执行一个时间片后会切换到下一个任务,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态,任务从保存到再加载的过程就是一次上下文切换。(这里不同于计算机用户线程到内核线程的上线文切换)
JVM中创建线程的两种方式
- new java.lang.Thread.start(); 这种方式只有调用start()方法的时候,才会真正的创建线程。
主要步骤有:- 创建对应的JavaThread的instance
- 创建对应的OSThread的instance
- 创建实际的底层操作系统的native thread
- 准备相应的JVM状态,比如ThreadLocal存储空间分配等
- 底层的native thread开始运行,调用java.lang.Thread生成的Object的run()方法
- 当java.lang.Thread生成的Object的run()方法执行完毕返回后,或者抛出异常终止后,终止native thread
- 释放JVM相关的thread的资源,清除对应的JavaThread和OSThread
- 使用JNI将一个native thread arrach到JVM中;
主要步骤有:- 通过JNI call AttachCurrentThread申请连接到执行的JVM实例
- JVM创建相应的JavaThread和OSThread对象
- 创建相应的java.lang.Thread的对象
- 一旦java.lang.Thread的Object创建之后,JNI就可以调用Java代码了
- 当通过JNI call DetachCurrentThread之后,JNI就从JVM实例中断开连接
- JVM清除相应的JavaThread, OSThread, java.lang.Thread对象
网友评论