java线程和操作系统线程

77 阅读3分钟

主要分成这两个方面: ·用户态的线程 ·内核态的线程

1.用户态的线程

第一阶段:
其实早期的时候,操作系统是没有线程的概念,线程是后面加进来的,操作系统刚开始只有进程,操作系统分配资源的最小单位是进程,进程与进程之间相关隔离,每个进程有自己的内存空间,文件描述符,CPU调度以进程作为最小调度单元;
第二阶段:
初期的多线程,线程是在用户空间下实现的。
什么意思?我们都知道内存分用户空间和系统空间,系统空间是给操作系统使用的,用户空间是应用程序使用的,应用程序如果需要访问系统空间,需要进行系统调用,从用户态切换到内核态。

那怎么在用户空间实现的多线程呢?
实际上是操作系统按进程维度来调度,操作系统是不去管你用户线程的切换的,应用程序自己在用户空间实现线程的创建、维护和调度。模型如下图:

image.png

当线程在用户空间下实现时,操作系统对线程的存在一无所知,操作系统只能看到进程而不能看到线程。所有的线程都是在用户空间实现。在操作系统看来,每一个进程只有个线程。

这种方式的好处之一就是即使操作系统不支持线程,也可以通过库函数来支持线程。在JDK1.1中,就用的绿色线程,而不是原始线程。

2.内核态的线程

在Java1.2之后.Linux中的JVM是基于pthread实现的,可以直接说Java 线程就是依赖操作系统实现的,是1:1的关系。现在的Java中线程的本质,其实就是操作系统中的线程.
实际上从Linux内核2.6开始,就把LinuxThread换成了新的线程实现方式NPTL,NPTL解决了LinuxThread中绝大多数跟POSIX标准不兼容的特性,并提供了更好的性能,可扩展性及可维护性等等。
LinuxThread使用的是1*1模型,即每一个用户态线程都有一个内核的管理实体跟其对应,这个内核对应的管理实体就是进程,又称LWP(轻量级进程)

我们知道,每个线程都有它自己的线程上下文,线程上下文包括线程的ID、栈、程序计数器、通用的寄存器等的合集。总觉得上下文这个词很模棱二可,但是发现也找不到更合适的词来描述。

线程有自己的独立的上下文,由操作系统调度,但是也有一个缺点,那就是线程消耗资源太大了,例如在linux上,一个线程默认的栈大小是1M,单机创建几万个线程就有点吃力了。所以后来在编程语言的层面上,就出现了协程这个东西。

协程的模式有点类似结合了上面二种方式,即是在用户态做线程资源切换,也让操作系统在内核层做线程调度。

协程跟操作系统的线程是有映射关系的,例如我们建了m个协程,需要在N个线程上执行,这就是m: n的方案,这n个线程也是靠操作系统调度实现。

另外协程是按需使用栈内存的,所以理论上可以轻轻松松创建百万级的协程。

目前协程这块支持的最好的是go语言,不过现在OpenJDK社区也正在为JDK增加协程的支持。