在传统的操做系统中,最核心的概念是“进程”,进程是对正在运行的程序的一个抽象。
进程的存在让“并行”成为了可能,在一个操做系统中,容许运行着多个进程,这些进程“看起来”是同时在运行的。
若是咱们的计算机同时运行着 web 浏览器、电子邮件客户端、即时通信软件例如QQ微信等多个进程,咱们感受这些进程都是同时在运行的,假设这台计算机搭配的是多个 CPU 或者 多核 CPU,那么这种多个进程并行的现象可能一点也不奇怪,彻底能够为每一个进程单独分配一个 CPU,这样就实现了多进程并行。
然而事实上,在计算机只有一个 CPU 的状况下,它也能给人类一种感受:多个进程同时在运行。但人类的感受每每是比较模糊的,不精确的。事实是因为 CPU 的计算速度很是地快,它能快速地在各个进程之间切换,在某一瞬间,CPU 只能运行一个进程,但一秒钟以内,它就能经过快速切换,让人产生多个进程同时在运行的错觉。
在操做系统中,为何在进程的基础上,又衍生出了线程的概念呢?web
每个进程在操做系统中都拥有独立的一块内存地址空间,该进程建立的全部线程共享这块内存,支持多线程的操做系统,会让线程做为 CPU 调度的最小单位。CPU 的时间片在不一样的线程之间进行分配。编程
基本上主流的操做系统都支持线程,也提供了线程的实现。而 Java 语言为了应对不一样硬件和操做系统的差别,提供了对线程操做的统一抽象,在 Java 中咱们使用 Thread 类来表明一个线程。
Thread 的具体实现可能会有不一样的实现方式:浏览器
内核线程是操做系统内核支持的线程,在内核中有一个线程表用来记录系统中的全部线程,建立或者销毁一个线程时,都须要涉及到系统调用,而后再内核中对线程表进行更新操做。对内核线程的阻塞以及其它操做,都涉及到系统调用,系统调用的代价都比较大,涉及到在用户态和内核态之间的来回切换。此外,内核内部有线程调度器,用于决定应该将 CPU 时间片分配个哪一个线程。
程序通常不会直接操做内核线程,而是使用内核线程的一种高级接口,轻量级进程。轻量级进程与内核线程之间的关系是 1:1,每个轻量级进程内部都有一个内核线程支持。微信
上图中, LWP 指 Light Weight Process,即轻量级进程;KLT 指 Kernel Level Thread,即内核线程。多线程
用户线程是程序或者编程语言本身实现的线程库,系统内核没法感知到这些线程的存在。用户线程的创建、同步、销毁和调度,都在用户态中完成,无须内核的帮助,不须要进行系统调用,这样的好处是对于线程的操做是很是高效的。在这种状况下,进程和用户线程的比例是 1 :N。编程语言
用户态线程面对如何阻塞线程时,会面临困难,阻塞一个用户态线程会出现把整个进程都阻塞的状况,多线程也就失去了意义。由于缺乏内核的支持,因此不少须要利用内核才能完成的工做,例如阻塞与唤醒线程、多 CPU 环境下线程的映射等,都须要用户程序去实现,实现起来会异常困难。性能
在这种混合实现下,既存在用户线程,也存在内核线程。用户态线程的建立、切换这些操做依然很高效,而且用户态实现的线程,比较容易加大线程的规模。须要操做系统内核支持的功能,则经过内核线程来作到,例如映射到不一样的处理器上、处理线程的阻塞与唤醒以及内核线程的调度等。这种实现依然会使用到轻量级进程 LWP,它是用户线程和内核线程之间的桥梁。spa
在 JDK1.2 以前, Java 的线程是使用用户线程实现的,在 JDK1.2 以后,Java 才采用操做系统原生支持的线程模型来实现,Java 线程模型的实现方式,主要取决于操做系统。对于 Oracle JDK 来讲,在 Windows 和 Linux 上的线程模型是采用一对一的方式实现的,即一条 Java 线程映射到一条轻量级进程(内核线程)。而在 Solaris 平台中,Java 则支持 1 :1 和 N : M 的线程模型。操作系统
Java 中的线程的状态有如下几种:New,Runnable,Waiting, TimedWaiting, Blocked,Terminated。线程
其中 Blocked 和 Waiting 有个重要的区别是,阻塞(Blocked)状态的线程在等待获取一个排他锁,例如线程在等待进入一个synchronized关键字包围的临界区时,就进入 Blocked 状态。而 Waiting 状态则是在等待被唤醒,或者等待一段时间。
《深刻理解 Java 虚拟机》第二版 - 周志明
《现代操做系统》第四版 - Andrew S. Tanenbaum