【多线程】(二)Java.lang.Process的思考

来源:互联网 发布:电视网络播放量排行榜 编辑:程序博客网 时间:2024/06/03 18:39

    “Process”很明显,是“进程”的意思,“多线程”系列的这篇文章,就是要来聊一聊进程的那些事。


一、前言

       最开始在做.NET开发的时候,对于“进程”以及“线程”的理解,来源于一幅漫画:

       1.计算机的核心是CPU,承担了全部的计算任务。它就好比一座工厂,时刻都在运行。为工厂中的每一个部件提供疏浚与处理的服务。

       

       2.假设这座工厂的电力无限,一次只能供给一个车间应用,也就是说一个车间开工的时候,其它车间都必须停工。当面的意思就是说一个CPU同一时间只能执行一个任务(进程)。

         

       3.进程就好比工厂的车间,任一时刻都只有一个车间在开工出产,其它车间都处于停工状态。当面的意思就是说,CPU在任一时刻总是只能运行单个进程,其它进程都处于非活动状态。

        

       4.一个车间里可以有很多个工人,它们协同实现一个任务。比如一个手机出产车间,张三负责主板的安装与调试,李四负责显示屏的测试与加工,王五负责手机零件的组装等。线程就好比这车间里的工人,一个进程包含了多个线程,它们各自负责实现自己的任务。

          

       5.车间里的空间是工人们共享的,比如车间里的很多房间(如:加工房、出产房、组装房等),这些车间里的每一个房间,工人们都是可以随意走动、收支的。这就意味者一个进程的内存空间是共享的,该进程中的全部线程都可以应用这片内存空间。

          

        至此,进程和线程关系部分的漫画就over了。详情参考:https://www.cnblogs.com/xinyuyuanm/archive/2013/05/19/3087596.html

        通过上述的描述,进程就相当于是windows系统中一个运行的.exe程序,而线程则是在这个.exe程序中跑的很多条并行业务线,比如好友视频、下载文件、数据传输等。


二、演变

       要想深入了解线程,就要先了解进程,这就要说起操作系统的“任务调度”。

       1.操作系统当前的调度模式

       在《操作系统》课程中,任务调度通常采用时间片轮转的抢占式调度方式实现,也就是说一个任务执行一小段时间后强制暂停,CPU去执行下一个任务,每个任务轮流执行。任务执行的一小段时间叫做时间片,任务正在执行时的状态叫运行状态,任务执行一段时间后强制暂停去执行下一个任务,被暂停的任务就处于就绪状态等待下一个属于它的时间片的到来。这样每个任务都能得到执行,由于CPU的执行效率非常高,时间片非常短,在各个任务之间快速地切换,给人的感觉就是多个任务在“同时进行”,这也就是我们所说的并发。

       我们都知道计算机的核心是CPU,它承担了所有的计算任务;而操作系统是计算机的管理者,它负责任务的调度、资源的分配和管理,统领整个计算机硬件;应用程序侧是具有某种功能的程序,程序是运行于操作系统之上的。

       进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。进程是一种抽象的概念,从来没有统一的标准定义。进程一般由程序、数据集合和进程控制块三部分组成。程序用于描述进程要完成的功能,是控制进程执行的指令集;数据集合是程序在执行时所需要的数据和工作区;程序控制块(Program Control Block,简称PCB),包含进程的描述信息和控制信息,是进程存在的唯一标志。
       进程具有的特征:
       动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的;
       并发性:任何进程都可以同其他进程一起并发执行;
       独立性:进程是系统进行资源分配和调度的一个独立单位;
       结构性:进程由程序、数据和进程控制块三部分组成。

        用两幅图来说明:

        1)

        

       2)

    

        图片、文案地址: http://www.importnew.com/21897.html

       如上图2所示,任务1,2,3可以理解为不同的进程,每次CPU时间片轮转后,执行的是具体进程中的线程。


       2.最初的调度模式

       计算机最初的设计是用来做计算,起初并没有进程和线程的区别,用户输入一条指令,计算机就执行一条指令,计算机在执行计算的过程,用户就得等待,不能够利用等待计算的时间来用计算机做其他操作。

       后来,随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了。于是就发明了线程,线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。一个标准的线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。而进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成。

       如图1:

       

        如图2:

     

       线程&进程:

       1.线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
       2.一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
       3.进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号),某进程内的线程在其它进程不可见;
       4.调度和切换:线程上下文切换比进程上下文切换要快得多。

       (该部分内容,引自:http://www.importnew.com/21897.html)


       3.多线程与多核

        keyword:运算核心、内核线程、

       多核(心)处理器是指在一个处理器上集成多个运算核心从而提高计算能力,也就是有多个真正并行计算的处理核心,每一个处理核心对应一个内核线程。内核线程(Kernel Thread, KLT)就是直接由操作系统内核支持的线程,这种线程由内核来完成线程切换,内核通过操作调度器对线程进行调度,并负责将线程的任务映射到各个处理器上。一般一个处理核心对应一个内核线程,比如单核处理器对应一个内核线程,双核处理器对应两个内核线程,四核处理器对应四个内核线程。
       现在的电脑一般是双核四线程、四核八线程,是采用超线程技术将一个物理处理核心模拟成两个逻辑处理核心,对应两个内核线程,所以在操作系统中看到的CPU数量是实际物理CPU数量的两倍,如你的电脑是双核四线程,打开“任务管理器\性能”可以看到4个CPU的监视器,四核八线程可以看到8个CPU的监视器。

         

      (双核四线程在Windows8下查看的结果)

       超线程技术就是利用特殊的硬件指令,把一个物理芯片模拟成两个逻辑处理核心,让单个处理器都能使用线程级并行计算,进而兼容多线程操作系统和软件,减少了CPU的闲置时间,提高的CPU的运行效率。这种超线程技术(如双核四线程)由处理器硬件的决定,同时也需要操作系统的支持才能在计算机中表现出来。

       程序一般不会直接去使用内核线程,而是去使用内核线程的一种高级接口——轻量级进程(Light Weight Process,LWP),轻量级进程就是我们通常意义上所讲的线程(我们在这称它为用户线程),由于每个轻量级进程都由一个内核线程支持,因此只有先支持内核线程,才能有轻量级进程。用户线程与内核线程的对应关系有三种模型:一对一模型、多对一模型、多对多模型,在这以4个内核线程、3个用户线程为例对三种模型进行说明。

       1.一对一模型:

       对于一对一模型来说,一个用户线程就唯一地对应一个内核线程(反过来不一定成立,一个内核线程不一定有对应的用户线程)。这样,如果CPU没有采用超线程技术(如四核四线程的计算机),一个用户线程就唯一地映射到一个物理CPU的线程,线程之间的并发是真正的并发。一对一模型使用户线程具有与内核线程一样的优点,一个线程因某种原因阻塞时其他线程的执行不受影响;此处,一对一模型也可以让多线程程序在多处理器的系统上有更好的表现。
       但一对一模型也有两个缺点:1.许多操作系统限制了内核线程的数量,因此一对一模型会使用户线程的数量受到限制;2.许多操作系统内核线程调度时,上下文切换的开销较大,导致用户线程的执行效率下降。

        

        2.多对一模型

       多对一模型将多个用户线程映射到一个内核线程上,线程之间的切换由用户态的代码来进行,因此相对一对一模型,多对一模型的线程切换速度要快许多;此外,多对一模型对用户线程的数量几乎无限制。但多对一模型也有两个缺点:1.如果其中一个用户线程阻塞,那么其它所有线程都将无法执行,因为此时内核线程也随之阻塞了;2.在多处理器系统上,处理器数量的增加对多对一模型的线程性能不会有明显的增加,因为所有的用户线程都映射到一个处理器上了。

        

      3.多对多模型

       多对多模型结合了一对一模型和多对一模型的优点,将多个用户线程映射到多个内核线程上。多对多模型的优点有:1.一个用户线程的阻塞不会导致所有线程的阻塞,因为此时还有别的内核线程被调度来执行;2.多对多模型对用户线程的数量没有限制;3.在多处理器的操作系统中,多对多模型的线程也能得到一定的性能提升,但提升的幅度不如一对一模型的高。
      在现在流行的操作系统中,大都采用多对多的模型。

       

       我通过上述内容的学习,1.理解了进程、线程以及二者之间关系的概念,2.通过和物理CPU内核做关联,了解到线程执行的本质以及操作系统任务调度的概念,上述内容,主要参考ImportNew中的文章:http://www.importnew.com/21897.html


三、基础

      如题所述,java.lang.Process(since 1.0)的思考,为了深入学习多线程,先了解进程,在jdk中,进程也有一个单独的类,在“java.lang.Process”当中,同时,和进程相关的类还有ProcessBuilder(since 1.5),ProcessEnvironmen,ProcessImpl三个类。

      jdk官方地址:https://docs.oracle.com/javase/8/docs/api/java/lang/Process.html

      

      通过翻阅JDK的api文档,jdk1.5之前启动和管理进程都必须通过Process类实现,1.5以及之后,通过ProcessBuilder就可以来做了,至于进程这块,目前掌握几个简单方法,如下:

      1.建立

      1)Java.lang.Runtime.exec 方法

      2)Java.lang.ProcessBuilder.start 方法


      2.列出所有进程

public class ProcessBuilder {public static void main(String[] args) {BufferedReader br = null;        Process process = null;        try {            process = Runtime.getRuntime().exec("tasklist");            br = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"));            String line = null;            System.out.println("列出所有正在运行的进程信息:");            while ((line = br.readLine()) != null) {                System.out.println(line);            }        } catch (IOException e) {            e.printStackTrace();        } finally {            if (br != null) {                try {                    br.close();                } catch (Exception e) {                    e.printStackTrace();                }            }            if(process!=null){                process.destroy();            }        }}}
       结果:

      

      3.其他常用API

- destroy() 杀掉子进程。- exitValue() 返回子进程的出口值。该方法不阻塞,如果此 Process 对象表示的子进程尚未终止,就会抛出IllegalThreadStateException异常,中止进程- getErrorStream() 获取子进程的错误流- getInputStream() 获取子进程的输入流- getOutputStream() 获取子进程的输出流,基本上不会用到输出流- waitFor() 导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。导致当前线程等待,如有必要,一直要等到由该 Process对象表示的进程已经终止。如果已终止该子进程,此方法立即返回。如果没有终止该子进程,调用的线程将被阻塞,直到退出子进程

       对于Process抽象类以及ProcessImpl这块,做简单介绍即好,侧重理解进程和线程之间的关系,脑子里有个对进程包含线程的宏观就ok。


       最后,分享一个链接,便于深入了解进程和线程与操作系统交互的文章:

       https://www.ibm.com/developerworks/cn/java/j-lo-processthread/

       

        That's all. tnx.

       

   




原创粉丝点击