您的位置:首页 > 编程语言 > Java开发

深入理解Java并发2——Java线程实现原理

2017-03-07 22:29 1036 查看
一 线程的实现

1.1 概念

线程是比进程更轻量级的调度执行单位,线程的引入,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、 文件I/O等),又可以独立调度(线程是CPU调度的基本单位)。

1.2 线程的实现方式

1.2.1 使用内核线程实现 (Java)

这种实现方式线程直接由操作系统内核支持。程序一般不会直接去使用内核线程,而是去使用内核线程的一种高级接口——轻量级进程,轻量级进程与内核线程之间是1:1的关系,称为一对一的线程模型 。



图片来源于《深入理解Java虚拟机》,KLT表示内核线程,LWP表示轻量级进程。

1.2.2 使用用户线程实现

用户线程完全建立在用户空间的线程库上,系统内核不能感知其存在。 用户线程的建立、 同步、 销毁和调度完全在用户态中完成,不需要内核的帮助。进程与用户线程为1:N的关系。Java早起曾采用该种实现,现已放弃。

1.2.3  使用用户线程加轻量级进程混合实现

这种实现方式将内核线程与用户线程一起使用,在这种混合实现下,既存在用户线程,也存在轻量级进程。 用户线程还是完全建立在用户空间中 。用户线程与轻量级进程为N:M的关系。

二 Java线程的实现

对于Sun JDK来说,它的Windows版与Linux版都是使用一对一的线程模型实现的,一条Java线程就映射到一条轻量级进程之中,因此Windows和Linux系统提供的线程模型就是一对一的,也就是实现方式1.2.1。 

三 Java线程调度

线程调度是指系统为线程分配处理器使用权的过程,主要调度方式有两种,分别是协同式线程调度和抢占式线程调度。

3.1 协同式线程调度

线程的执行时间由线程本身来控制,线程把自己的工作执行完了之后,要主动通知系统切换到另外一个线程上。  

优点:实现简单,而且由于线程要把自己的事情干完后才会进行线程切换,切换操作对线程自己是可知的,所以没有什么线程同步的问题。  

缺点:线程执行时间不可控制,甚至如果一个线程编写有问题,一直不告知系统进行线程切换,那么程序就会一直阻塞在那里。  

3.2 抢占式线程调度

每个线程由系统来分配执行时间,线程的切换不由线程本身来决定(在Java中,Thread.yield()可以让出执行时间,但是要获取执行时间的话,线程本身是没有什么办法的)。 在这种实现线程调度的方式下,线程的执行时间是系统可控的,也不会有一个线程导致整个进程阻塞的问题,Java使用的线程调度方式就是抢

占式调度 。

3.3 优先级

虽然Java线程调度是系统自动完成的,但是我们还是可以“建议”系统给某些线程多分配一点执行时间,另外的一些线程则可以少分配一点——这项操作可以通过设置线程优先级来完成。Java语言一共设置了10个级别的线程优先级(Thread.MIN_PRIORITY至Thread.MAX_PRIORITY),在两个线程同时处于Ready状态时,优先级越高的线程越容易被系统选择执行。 

但是,Java的线程是通过映射到系统的原生线程上来实现的,所以线程调度最终还是取决于操作系统,虽然现在很多操作系统都提供线程优先级的概念,但是并不见得能与Java线程的优先级一一对应;并且,优先级可能会被系统自行改变 。因此,我们不能在程序中通过优先级来完全准确地判断一组状态都为Ready的线程将会先执行哪一个 。

3.4 状态转换

Java语言定义了5种线程状态,在任意一个时间点,一个线程只能有且只有其中的一种状态 :

3.4.1 新建(New):创建尚未启动。

3.4.2 运行(Runable):包括了操作系统线程状态中的Running和Ready,处于此状态的线程有可能正在执行,也有可能正在等待着CPU为它分配执行时间。

3.4.3 无限期等待(Waiting) :等待被其他线程显式地唤醒 。

3.4.4 限期等待(Timed Waiting):一定时间之后它们会由系统自动唤醒 。如sleep()

3.4.5 阻塞(Blocked) :“阻塞状态”在等待着获取到一个排他锁,这个事件将在另外一个线程放弃这个锁的时候发生 。

3.4.6 结束(Terminated)  :已终止线程的线程状态,线程已经结束执行。



图片来源于《深入理解Java虚拟机》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息