JVM学习之java线程实现&调度和状态转换

版权声明:本文为博主原创文章,转载希望能注明出处,感谢。 https://blog.csdn.net/u010126792/article/details/82992961

以下blog内容来自《深入理解Java虚拟机_JVM高级特性与最佳实践》感谢作者!

1 谨慎使用java 多线程  

如何提升效率:

     使用java时推荐利用多线程处理一些操作绝大多数情况下确实能提高效率,提高效率的原理在哪里呢,为什么说绝大多说情况呢。

       在CPU单核时代,我们知道某一时刻工作的线程只能是一条,那多线程为什么还能提高效率呢,因为类似IO这种阻塞操作很多时候CPU需要等待文件被从硬盘读到内存之后才能干活(IO密集型操作不适合多线程,因为io瓶颈无法避免,所以这里只是举个简单例子说明情况),那就存在阻塞过程中CPU一直在等待,如果这个时候另开一个线程让cpu去干活就大大提高了效率。

      多CPU时代,同一时刻可以多个线程工作更能提升工作效率。

为什么要谨慎使用:

多线程工作原理:cpu通过给每个线程分配cpu时间片,不停地切换线程的状态来实现多线程(感觉同时执行是因为时间片较短),线程的创建和状态切换是不容忽视的开销。

当前任务执行一个时间片后会切换到下一个任务,在切换之前,上一个任务的状态会被保存下来,下次切换回这个任务时,可以再加载这个任务的状态,任务从保存到再加载的过程就是一次上下文切换。

考虑一种情况就是线程状态切换的时间比线程工作时间还耗费时间或者相差不多时,此时多线程未必能提高效率。

2 线程实现方式

线程是比进程更轻量级的调度执行单位,线程把一个进程的资源分配和执行调度分开,各个线程既共享进程资源又独立调度。

实现线程主要有三种方式:

使用内核线程实现,使用用户线程实现和使用用户线程加轻量级进程混合实现。

2.1 使用内核线程实现

内核线程就是直接由操作系统支持的线程,这种线程由内核来完成线程的切换,内核通过操纵调度器进行调度,并负责将线程的任务映射到各个处理器上。

程序一般不会直接去使用内核线程,而失去使用内核线程的一种高级接口-轻量级进程,每个轻量级进程都是由一个内核线程支持,因此只有先支持内核线程才能有轻量级进程。

轻量级进程的局限:

(1)由于是基于内核线程实现的,所以各种线程操作,如创建,析构和同步都需要进行系统调用,系统调用需要在用户态和内核态之间来回切换很消耗资源。

(2)每个轻量级进程都需要一个内核线程的支持,因此会消耗内核资源,所以一个系统支持的轻量级进程的数目是有限的。

2.2 使用用户线程实现

狭义上来说用户线程指的是完全建立在用户空间的线程库上构建线程框架,系统内核无法感知用户线程存在的实现。

用户线程的建立,同步,销毁和调度完全在用户态中完成,不需要内核的帮忙,甚至这种线程如果实现得当不需要切换到内核态,因此操作可以非常快速和高效,线程数目也可以 更大。

优势劣势:

系统用户线程的优势在于不需要系统内核支援,劣势也在于没有系统内核的支援,所有操作都需要用户自己处理,可能实现起来更加复杂,此种方式在语言中较少使用。

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

此种方式将内核线程与用户线程一起使用,混合模式下既存在用户线程又存在轻量级进程。用户线程的创建,切换,析构等操作依然高效,利用轻量级进程作为用户线程和内核线程之间的桥梁,可以使用内核提供的线程调度功能及处理器映射,并且用户线程的系统调用要通过轻量级线程来完成,大大降低了整个进程被完全阻塞的风险。

2.4 java线程的实现方式

java Jdk1.2之前是基于称为'绿色线程'的用户线程实现的,Jdk1.2中线程模型替换成了基于操作系统原生线程模型来实现。

Sun JDK中,windows和Linux版都是使用一对一的线程模型实现,一条java线程映射到一条轻量级进程中,二Solaris平台中可以同时支持一对一和多对多。

3 java 线程调度

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

如果使用协同式调度的多线程系统,线程的执行时间由线程本身来控制,线程把自己的工作执行完了之后,要主动通知系统切换到另外一个线程上。

特点:

协同式多线程系统的优点是实现简单,自己干完活之后才切换线程,所以对切换现成的操作自己是知道的,没有线程同步的问题。但存在的问题也很明显,线程执行时间是不可控的,如果一个线程编写的有问题可能会一直阻塞在那里。

抢占式调用的多线程系统每个线程将由系统来分配执行时间,线程的切换不由线程本身来决定,这种方式下现成的执行时间是系统可控的,不会有一个线程导致整个进程阻塞的问题,java使用的就是这种抢占式调度。java线程还可以设置优先级,但这种优先级是不可靠的。

4 线程状态的转换

java语言定义了五种线程状态,在任意一个时间点线程只能有且仅有其中的一种状态。

五种状态如下:

新建(New):创建后尚未启动的线程处于这种状态

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

无限期等待(Waiting):处于这种状态的线程不会被分配cpu时间,它们要等待被其他线程显式的唤醒。

类似没有设置Timeout参数的Object.wait(),没有设置Timeout参数的Thread.join()方法

限期等待(Timed Waiting):处于这种状态的线程也不会被分配cpu执行时间,不过无须等待被其他线程显式的唤醒,一定时间之后会由系统自动唤醒。

阻塞(Blocked):线程被阻塞了,阻塞与等待状态的区别是,阻塞状态在等待着获取到一个排它锁,这个事件将在另外一个线程放弃这个锁时发生,而等待状态则是在等待一段时间或者唤醒动作的发生,在程序等待进入同步区域的时候,线程将进入这种状态。

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

                                                                                        

猜你喜欢

转载自blog.csdn.net/u010126792/article/details/82992961