Thread的底层模型
Thread类中的每一个实例代表JVM中的一个线程。
JVM中的线程在Linux上称为轻量级进程
, 和进程本质无区别,
在Windows上使用系统线程。
下面着重说一下在Linux中对应的轻量级进程概念
,
如下图, 进程和线程一样,都是用于一行一行的执行代码的,唯一的区别就是多个线程
可以共享同一个进程的内存空间,
而进程之间的内存是隔离开来的。
所以在Linux实现中,将进程和线程都称之为task
(如下图), 只是可能有些task共享同一块内存空间,称之为进程组(process group)
。
下面在Linux上用一段代码验证一下,在主线程里和一个新线程里同时开启死循环:
使用 javac ThreadTest.java && java ThreadTest
运行代码,使用jps找到我们刚刚运行的ThreadTest
进程id,
再pstree -p 3026
一下,查看这个进程有哪些线程组成,可以看到下图,其实java进程中,又开启了许多linux意义上的进程,每一个都有独立的id,每一个都代表linux上的一个任务,
我们再运行top -n 1 -H -p 3026
看一下进程中的每个线程占了多少CPU,可以看到下图中,有两个线程吃CPU吃的非常多,因为它是我们刚刚写的两个死循环的线程,
这时候我们再运行一下jstack 3026
查看一下jvm进程中正在运行的线程,可以看到有一个线程的nid是0xbde
,这是一个16进制的数字,我们转移一下变成了3038
,这和我们上面看到的占用CPU最多的进程idPID
是一样的,
还有一个是0xbd3
,翻译成10进制是3027
, 可以看到也和刚刚其中一个PID吻合,
由此我们可以得出,在Linux中,JVM中的一个线程其实就是一个进程,只是在JVM进程中的表现形式是16进制,但是和Linux中的PID是吻合的,
所以在Linux的内核调度中,JVM的线程和进程是一样的,可以称之为轻量级进程
或者task
, 和进程的不同之处就在于和同一个进程中的其他轻量级进程
共享了同一块内存,
在Windows中有稍许不同,Windows中线程和进程的地位不同,这里不展开讨论,有兴趣可以查阅资料。
总结
这里讨论一下JVM
中的线程实现直接和操作系统实现绑定的好处,
好处就是,实现简单,直接依赖于操作系统的调度器,操作系统让线程执行就执行,暂停就暂停,因为自己实现一个调度器非常复杂,直接依赖操作系统的调度器可以让代码大大简化。
缺点:
-
占用资源多,每个JVM中的线程实现都对应linux的进程,都有自己独立的一套方法栈,会占用系统内核的空间
-
上下文切换慢,CPU每次切换线程执行的时候,都要将当前线程的环境保存到内存中,下次恢复执行的时候,还要从内存中恢复线程环境,因此非常的慢
-
不灵活,无法实现灵活的优先级,JVM的线程很依赖系统内核的调度,内核决定哪个线程先执行,哪个线程后执行,无法做到让某个线程多执行一段时间,或者让某个线程优先级别更高一些,虽然JVM的线程可以设置优先级,但是还是依赖于内核,用处不大