“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.

【多线程】(二)Java.lang.Process的思考相关推荐

  1. 使用Process运行程序提示error: incompatible types: java.lang.Process cannot be converted to android.os.Proces

    一.在android framework sevice里面 添加下面的代码,使用Process  java中运行第三方程序,编译的时候提示 error: incompatible types: jav ...

  2. JDK1.8源码(二)——java.lang.Integer 类

    上一篇博客我们介绍了 java.lang 包下的 Object 类,那么本篇博客接着介绍该包下的另一个类 Integer.在前面 浅谈 Integer 类 博客中我们主要介绍了 Integer 类 和 ...

  3. java.lang包中的常用类

    java.lang包 java.lang.Boolean类 java.lang.Byte类 java.lang.Character java.lang.Character.Subset类 java.l ...

  4. 【错误记录】Android 中调用 Process 命令行执行指令 ( java.lang.IllegalThreadStateException: process hasn‘t exited )

    文章目录 一.报错信息 二.解决方案 一.报错信息 2021-05-07 13:24:24.672 29512-29512/kim.hsl.a7_zip E/AndroidRuntime: FATAL ...

  5. 深入研究java.lang.Runtime类,Process类

    2019独角兽企业重金招聘Python工程师标准>>> 一.概述 Runtime类封装了运行时的环境.每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行 ...

  6. 面试题汇总二 Java 多线程篇

    前言 题目汇总来源 史上最全各类面试题汇总,没有之一,不接受反驳 面试题汇总一 Java 语言基础篇 面试题汇总二 Java 多线程篇 面试题汇总三 Java 集合篇 面试题汇总四 JVM 篇 面试题 ...

  7. Java读书笔记(4)-多线程(二)

    Java读书笔记(4)-多线程(二) 2016-1-2 线程通信 传统的线程通信 Object类提供了wait(),notify()和notifyAll三个方法 适用情况:synchronized修饰 ...

  8. 【Android】java.lang.SecurityException: getDeviceId: Neither user xxxxx nor current process has andro

    错误异常 产生原因 解决办法 参考链接 错误异常 java.lang.SecurityException: getDeviceId: Neither user xxxxx nor current pr ...

  9. 关于7.0手机爱贝支付转圈问题-java.lang.SecurityException: getSubscriberId: Neither user 10191 nor current process

    最近测试发现爱贝渠道的包在支付的时候一直"转圈",没有弹出支付界面. 看log发现是: java.lang.SecurityException: getSubscriberId: ...

最新文章

  1. 自定义标签 (转载)
  2. 超干货 | 在线教育增长实操者案例分享:如何玩转教育增长模型?
  3. Eclipse不给提示no default proposals
  4. python什么是空类型_在Python中创建真正的空类型
  5. 流媒体通信协议HLS与DASH的对比
  6. 存储过程的参数可以使用sql的函数
  7. Unity 协程深入解析与原理
  8. 软件工程的持续交付(CDF)和规范
  9. Java计划任务:ScheduledThreadPoolExecutor
  10. python是否安装numpy_python 怎么查看安装numpy的版本
  11. Scratch少儿编程案例~走迷宫游戏
  12. python自动补全快捷键_Python快捷键的干货来啦!快来看看你掌握了几个~
  13. 微信公众号--根据用户的opneId发送模版消息
  14. 水平凡 创建新的插件
  15. 数据结构(八)——后缀表达式
  16. 如何推导欧拉公式e^iθ=cosθ+i*sinθ
  17. 独立钻石跳棋问题的C++实现
  18. 培养学生计算机绘画水平,电脑绘画教导方法
  19. java奥特曼对战小怪兽_“奥特曼攻打小怪兽”java打怪升级第一步
  20. 重启linux后无法ssh登录

热门文章

  1. 笔试题-2023-思远半导体-数字IC设计【纯净题目版】
  2. ZSTU2019校赛 Problem D Lis(线性基dp)
  3. 中国定制家具行业深度调研及投资前景预测报告
  4. matplotlib 辅助线
  5. Android下最好用的免费在线影视应用是哪个?
  6. hive尚硅谷实战案例统计youtube视频热度
  7. 成为第一没有捷径:AI新势力MindSpore成长秘籍 | 源创者说
  8. 【机器学习笔记之五】用ARIMA模型做需求预测用ARIMA模型做需求预测
  9. python查看迭代器可迭代次数
  10. 一个可以不被广告拦截器拦截的弹出窗口