精华内容
下载资源
问答
  • 进程

    万次阅读 2019-03-28 21:04:35
    线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。 线程是程序执行的一条路径...

    进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体。它不只是程序的代码,还包括当前的活动,通过程序计数器的值和处理寄存器的内容来表示。

    进程的概念主要有两点:

    进程是一个实体,每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
    进程是一个“执行中的程序”,程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。
    进程的基本状态

    阻塞态:等待某个事件的完成;
    就绪态:等待系统分配处理器以便运行;
    执行态:占有处理器正在运行。

    执行态 -> 阻塞态:往往是由于等待外设,等待主存等资源分配或等待人工干预而引起的。
    阻塞态 -> 就绪态:则是等待的条件已满足,只需分配到处理器后就能运行。
    执行态 -> 就绪态:不是由于自身原因,而是由外界原因使运行状态的进程让出处理器,这时候就变成就绪态。例如时间片用完,或有更高优先级的进程来抢占处理器等。
    就绪态 -> 执行态:系统按某种策略选中就绪队列中的一个进程占用处理器,此时就变成了运行态
    进程调度

    上下文切换

    线程/进程的上下文(以下统称为:上下文)主要包含两个部分:寄存器(尤其是 PC)和操作系统需要的特定数据(PCB)。上下文切换(context switch),是一个存储和重建 CPU 的过程,完整的上下文会涉及到这两部分的切换,旧的上下文被保存,新的上下文被加载。

    当系统发生中断或者 OS 进行线程调度时会进行上下文切换。

    调度种类

    高级、中级和低级调度作业从提交开始直到完成,往往要经历下述三级调度:

    高级调度:又称为作业调度,它决定把后备作业调入内存运行;
    中级调度:又称为在虚拟存储器中引入,在内、外存对换区进行进程对换。
    低级调度:又称为进程调度,它决定把就绪队列的某进程获得CPU;
    非抢占式调度与抢占式调度

    非抢占式:分派程序一旦把处理机分配给某进程后便让它一直运行下去,直到进程完成或发生进程调度进程调度某事件而阻塞时,才把处理机分配给另一个进程。

    抢占式:操作系统将正在运行的进程强行暂停,由调度程序将CPU分配给其他就绪进程的调度方式。

    调度策略的设计

    响应时间:从用户输入到产生反应的时间
    周转时间:从任务开始到任务结束的时间
    平均周转时间:周转总时间除以作业个数
    CPU任务可以分为交互式任务和批处理任务,调度最终的目标是合理的使用CPU,使得交互式任务的响应时间尽可能短,用户不至于感到延迟,同时使得批处理任务的周转时间尽可能短,减少用户等待的时间。

    调度算法

    FCFS:调度的顺序就是任务到达就绪队列的顺序。对短作业不公平。

    SJF:最短的作业(CPU区间长度最小)最先调度。

    HRN:最高响应比优先法,是 FCFS 和 SJF 的综合平衡,响应比R定义如下: R =(W+T)/T 。

    优先权调度:每个任务关联一个优先权,调度优先权最高的任务。

    Round-Robin(RR):设置一个时间片,按时间片来轮转调度

    多级队列调度

    按照一定的规则建立多个进程队列
    不同的队列有固定的优先级(高优先级有抢占权)
    不同的队列可以给不同的时间片和采用不同的调度方法
    多级反馈队列:在多级队列的基础上,任务可以在队列之间移动,更细致的区分任务。可以根据“享用”CPU时间多少来移动队列,阻止“饥饿”。

    进程同步

    临界资源与临界区

    在操作系统中,进程是占有资源的最小单位(线程可以访问其所在进程内的所有资源,但线程本身并不占有资源或仅仅占有一点必须资源)。但对于某些资源来说,其在同一时间只能被一个进程所占用。这些一次只能被一个进程所占用的资源就是所谓的临界资源。典型的临界资源比如物理上的打印机,或是存在硬盘或内存中被多个进程所共享的一些变量和数据等(如果这类资源不被看成临界资源加以保护,那么很有可能造成丢数据的问题)。

    对于临界资源的访问,必须是互斥进行。也就是当临界资源被占用时,另一个申请临界资源的进程会被阻塞,直到其所申请的临界资源被释放。而进程内访问临界资源的代码被成为临界区。

    对于临界区的访问过程分为四个部分:

    进入区:查看临界区是否可访问,如果可以访问,则转到步骤二,否则进程会被阻塞
    临界区:在临界区做操作
    退出区:清除临界区被占用的标志
    剩余区:进程与临界区不相关部分的代码
    解决临界区问题可能的方法:

    一般软件方法
    关中断方法
    硬件原子指令方法
    信号量方法
    信号量

    信号量是一个确定的二元组(s,q),其中s是一个具有非负初值的整形变量,q是一个初始状态为空的队列,整形变量s表示系统中某类资源的数目:

    当其值 >= 0 时,表示系统中当前可用资源的数目
    当其值 < 0 时,其绝对值表示系统中因请求该类资源而被阻塞的进程数目
    除信号量的初值外,信号量的值仅能由 P 操作和 V 操作更改,操作系统利用它的状态对进程和资源进行管理

    互斥锁:同一时间只能有一个线程访问加锁的数据。
    自旋锁:互斥锁的一种实现,如果自旋锁已经被别的执行单元保持,调用者就一直 循环等待 是否该自旋锁的保持者已经释放了锁。
    读写锁:一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。写者是排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读者又有写者。
    阻塞锁:与自旋锁不同,改变了线程的运行状态。让线程进入阻塞状态进行等待,当获得相应的信号(唤醒,时间) 时,才可以进入线程的准备就绪状态,准备就绪状态的所有线程,通过竞争,进入运行状态。
    在Java中synchronized,ReentrantLock,Object.wait() / notify()都属于阻塞锁。
    可重入锁:也叫做递归锁,指的是同一线程上该锁是可重入的,对于不同线程则相当于普通的互斥锁。
    公平锁:加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得。
    非公平锁:加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待。ReentrantLock中的lock()默认就是非公平锁。
    悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。加锁的时间可能会很长,也就是说悲观锁的并发访问性不好。
    乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。乐观锁不能解决脏读的问题,可以通过添加时间戳和版本来来解决。
    死锁

    死锁是指多个进程因循环等待资源而造成无法执行的现象。死锁会造成进程无法执行,同时会造成系统资源的极大浪费(资源无法释放)。

    死锁产生的四个必要条件

    互斥使用:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

    不可抢占:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

    请求和保持:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

    循环等待:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

    死锁避免

    银行家算法:判断此次请求是否造成死锁若会造成死锁,则拒绝该请求。

    CAS

    比较并交换(compare and swap, CAS),是原子操作的一种,可用于在多线程编程中实现不被打断的数据交换操作。该操作通过将内存中的值与指定数据进行比较,当数值一样时将内存中的数据替换为新的值。

    在使用上,通常会记录下某块内存中的旧值,通过对旧值进行一系列的操作后得到新值,然后通过CAS操作将新值与旧值进行交换。如果这块内存的值在这期间内没被修改过,则旧值会与内存中的数据相同,这时CAS操作将会成功执行使内存中的数据变为新值。如果内存中的值在这期间内被修改过,则一般来说旧值会与内存中的数据不同,这时CAS操作将会失败,新值将不会被写入内存。

    进程间通信

    本地进程间通信的方式有很多,可以总结为下面四类:

    消息传递(管道、FIFO、消息队列)
    同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)
    共享内存(匿名的和具名的)
    远程过程调用(Solaris门和Sun RPC)
    子进程

    在 Unix 和类 Unix 系统中,子进程通常为系统调用 fork 的产物。调用 fork 后的父子进程会运行在不同的内存空间中,当 fork 发生时两者的内存空间有着完全相同的内容,对内存的写入和修改、文件的映射都是独立的,两个进程不会相互影响。除此之外,子进程几乎是父进程的完整副本。

    既然父进程和子进程拥有完全相同的内存空间并且两者对内存的写入都不会相互影响,那么是否意味着子进程在 fork 时需要对父进程的内存进行全量的拷贝呢?

    在一些早期的 *nix 系统上,系统调用 fork 确实会立刻对父进程的内存空间进行复制,但是在今天的多数系统中, fork 并不会立刻触发这一过程,而是在内存被修改时,才会进行数据复制(Copy-On-Write)。

    当 fork 函数调用时,父进程和子进程会被 Kernel 分配到不同的虚拟内存空间中,所以在两个进程看来它们访问的是不同的内存:

    在真正访问虚拟内存空间时,Kernel 会将虚拟内存映射到物理内存上,所以父子进程共享了物理上的内存空间;
    当父进程或者子进程对共享的内存进行修改时,共享的内存才会以页为单位进行拷贝,父进程会保留原有的物理空间,而子进程会使用拷贝后的新物理空间;
    线程

    线程是 操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

    线程是独立调度和分派的基本单位。线程可以操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。

    同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈,自己的寄存器环境,自己的线程本地存储。

    线程的属性

    轻型实体:线程中的实体基本上不拥有系统资源,只是有一点必不可少的、能保证独立运行的资源。线程的实体包括程序、数据和TCB。线程是动态概念,它的动态特性由线程控制块TCB(Thread Control Block)描述。TCB包括以下信息:

    线程状态。
    当线程不运行时,被保存的现场资源。
    一组执行堆栈。
    存放每个线程的局部变量主存区。
    访问同一个进程中的主存和其它资源。
    用于指示被执行指令序列的程序计数器、保留局部变量、少数状态参数和返回地址等的一组寄存器和堆栈。

    独立调度和分派的基本单位:在多线程OS中,线程是能独立运行的基本单位,因而也是独立调度和分派的基本单位。由于线程很“轻”,故线程的切换非常迅速且开销小(在同一进程中的)。

    可并发执行:在一个进程中的多个线程之间,可以并发执行,甚至允许在一个进程中所有线程都能并发执行;同样,不同进程中的线程也能并发执行,充分利用和发挥了处理机与外围设备并行工作的能力。

    共享进程资源:在同一进程中的各个线程,都可以共享该进程所拥有的资源,这首先表现在:所有线程都具有相同的地址空间(进程的地址空间),这意味着,线程可以访问该地址空间的每一个虚地址;此外,还可以访问进程所拥有的已打开文件、定时器、信号量机构等。由于同一个进程内的线程共享内存和文件,所以线程之间互相通信不必调用内核。

    线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。
    线程是程序执行的一条路径,在多线程的OS中,线程是调度和分配的基本单位,而进程是拥有资源的基本单位。

    进程 vs 线程

    线程本质就是堆栈,当一段程序在执行,能代表它的是他的过去和现在。过去 在堆栈中,现在 则是 CPU 的所有寄存器,如果我们要挂起一个线程,我们把寄存器也保存到堆栈中,我们就具有它的所有状态,可以随时恢复它。

    进程的本质是地址空间,当我们切换线程的时候,同时切换它的地址空间(通过修改MMU即可),则认为发生了进程切换。

    中断

    中断(英语:Interrupt)是指 处理器接收到来自硬件或软件的信号,提示发生了某个事件,应该被注意,这种情况就称为中断。

    通常,在接收到来自外围硬件(相对于中央处理器和内存)的异步信号,或来自软件的同步信号之后,处理器将会进行相应的 硬件/软件 处理。发出这样的信号称为进行中断请求(interrupt request,IRQ)。硬件中断导致处理器通过一个运行信息切换(context switch)来保存执行状态(以程序计数器和程序状态字等寄存器信息为主);软件中断则通常作为CPU指令集中的一个指令,以可编程的方式直接指示这种运行信息切换,并将处理导向一段中断处理代码。中断在计算机多任务处理,尤其是即时系统中尤为有用。

    硬件中断

    由硬件发出或产生的中断称为硬中断,按硬中断事件的来源和实现手段可将中断划分为外中断和内中断:

    外中断:又称为中断或异步中断,是指 来自处理器以外的中断信号,包括时钟中断、键盘中断、外部设备中断等。外中断又分为可屏蔽中断和不可屏蔽中断,各个中断具有不同的优先级,表示事件的紧急程度,在处理高一级中断时,往往会部分或全部屏蔽低等级中断。
    内中断:又称为异常或同步中断(产生时必须考虑与处理器时钟同步),是指 来自处理器内部的中断信号,通常是由于程序执行过程中,发现与当前指令关联的、不正常的或错误的事件。
    软件中断

    软件中断:是一条CPU指令,用以自陷一个中断。由于 软中断指令通常要运行一个切换CPU至内核态(Kernel Mode/Ring 0)的子例程,它常被用作实现系统调用(System call)。

    处理器通常含有一个内部中断屏蔽位,并允许通过软件来设定。一旦被设定,所有外部中断都将被系统忽略。这个屏蔽位的访问速度显然快于中断控制器上的中断屏蔽寄存器,因此可提供更快速地中断屏蔽控制。

    中断尽管可以提高计算机处理性能,但 过于密集的中断请求/响应反而会影响系统性能。这类情形被称作中断风暴(interrupt storm)。

    内核态&用户态

    内核态是一种 CPU 的特权态,CPU 可以在特权态下执行特殊的指令,访问这个特权态才运行访问的资源。上面提到的三种中断形式:外中断、异常中断、软件中断,均可使 OS 从用户态切换到内核态。

    内核态切换

    内核态切换不一定进行上下文切换。先考虑简单的内核态切换——获取当前系统时间。CPU 从用户态切换到内核态,保存用户态的寄存器数据,执行内核代码以获取数据,将数据存储到调用者可访问的存储器或寄存器,恢复用户态的寄存器数据并返回。这里未进行完整的上下文切换,只是涉及用户态到内核态的模式切换。

    现在考虑一个系统调用,该调用会阻塞调用者,直到发生某些事件或数据可用为止。在这种情况下,内核将被迫保存调用者的完整上下文,将其标记为 阻塞态,以便调度程序在该事件或数据到达之前无法运行它。这时调度程序会加载另一个就绪线程/进程的上下文。这里的内核态切换就会导致上下文切换。

    展开全文
  • 1. 先根据进程名查看进程id ps aux | grep 进程名(或者ps -ef | grep 进程名) y@ubuntu:~$ ps aux | grep bitcoind y 2708 101 12.1 1611172 488580 ? Ssl Aug22 32:04 bitcoind -daemon -connect=172.16.247.139 ...
    1. 先根据进程名查看进程id

    ps aux | grep 进程名(或者ps -ef | grep 进程名)

    y@ubuntu:~$ ps aux | grep bitcoind
    y          2708  101 12.1 1611172 488580 ?      Ssl  Aug22  32:04 bitcoind -daemon -connect=172.16.247.139
    y          3564  0.0  0.0  21536  1092 pts/0    S+   00:23   0:00 grep --color=auto bitcoind
    

    可以看到,bitcoind进程的pid是2708

    2.通过进程id查看占用的端口

    netstat -nap | grep 进程id

    y@ubuntu:~$ netstat -nap | grep 2708
    (Not all processes could be identified, non-owned process info
     will not be shown, you would have to be root to see it all.)
    tcp        0      0 127.0.0.1:8332          0.0.0.0:*               LISTEN      2708/bitcoind       
    tcp6       0      0 ::1:8332                :::*                    LISTEN      2708/bitcoind 
    

    可以看到,pid=2708的进程占用的端口号是8332

    3.通过端口号查看占用的进程id

    netstat -nap | grep 端口号

    y@ubuntu:~$ netstat -nap | grep 8332
    (Not all processes could be identified, non-owned process info
     will not be shown, you would have to be root to see it all.)
    tcp        0      0 127.0.0.1:8332          0.0.0.0:*               LISTEN      2708/bitcoind       
    tcp6       0      0 ::1:8332                :::*                    LISTEN      2708/bitcoind  
    

    可以看到,占用8332端口的是进程的pid是2708,名称是bitcoind

    展开全文
  • 进程和线程的区别(超详细)

    万次阅读 多人点赞 2019-10-03 21:57:46
    进程和线程 进程 一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。 线程 进程中的一个执行任务(控制单元),负责...

    进程和线程

    进程

    一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。

    任务管理器

    线程

    进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。

    与进程不同的是同类的多个线程共享进程的方法区资源,但每个线程有自己的程序计数器虚拟机栈本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。

    Java 程序天生就是多线程程序,我们可以通过 JMX 来看一下一个普通的 Java 程序有哪些线程,代码如下。

    public class MultiThread {
    	public static void main(String[] args) {
    		// 获取 Java 线程管理 MXBean
    		ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
    		// 不需要获取同步的 monitor 和 synchronizer 信息,仅获取线程和线程堆栈信息
    		ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
    		// 遍历线程信息,仅打印线程 ID 和线程名称信息
    		for (ThreadInfo threadInfo : threadInfos) {
    			System.out.println("[" + threadInfo.getThreadId() + "] " + threadInfo.getThreadName());
    		}
    	}
    }
    

    上述程序输出如下(输出内容可能不同,不用太纠结下面每个线程的作用,只用知道 main 线程执行 main 方法即可):

    [6] Monitor Ctrl-Break //监听线程转储或“线程堆栈跟踪”的线程
    [5] Attach Listener //负责接收到外部的命令,而对该命令进行执行的并且把结果返回给发送者
    [4] Signal Dispatcher // 分发处理给 JVM 信号的线程
    [3] Finalizer //在垃圾收集前,调用对象 finalize 方法的线程
    [2] Reference Handler //用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收的线程
    [1] main //main 线程,程序入口
    

    从上面的输出内容可以看出:一个 Java 程序的运行是 main 线程和多个其他线程同时运行

    进程与线程的区别总结

    线程具有许多传统进程所具有的特征,故又称为轻型进程(Light—Weight Process)或进程元;而把传统的进程称为重型进程(Heavy—Weight Process),它相当于只有一个线程的任务。在引入了线程的操作系统中,通常一个进程都有若干个线程,至少包含一个线程。

    根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位

    资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

    包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

    内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的

    影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

    执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行

    从 JVM 角度说进程和线程之间的关系(重要)

    图解进程和线程的关系

    下图是 Java 内存区域,通过下图我们从 JVM 的角度来说一下线程和进程之间的关系。

    在这里插入图片描述

    从上图可以看出:一个进程中可以有多个线程,多个线程共享进程的方法区 (JDK1.8 之后的元空间)资源,但是每个线程有自己的程序计数器虚拟机栈本地方法栈

    程序计数器为什么是私有的?

    程序计数器主要有下面两个作用:

    1. 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
    2. 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

    需要注意的是,如果执行的是 native 方法,那么程序计数器记录的是 undefined 地址,只有执行的是 Java 代码时程序计数器记录的才是下一条指令的地址。

    所以,程序计数器私有主要是为了线程切换后能恢复到正确的执行位置

    虚拟机栈和本地方法栈为什么是私有的?

    • 虚拟机栈:每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
    • 本地方法栈:和虚拟机栈所发挥的作用非常相似,区别是: 虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。

    所以,为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的。

    一句话简单了解堆和方法区

    堆和方法区是所有线程共享的资源,其中堆是进程中最大的一块内存,主要用于存放新创建的对象 (所有对象都在这里分配内存),方法区主要用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

    多进程和多线程区别

    多进程:操作系统中同时运行的多个程序

    多线程:在同一个进程中同时运行的多个任务

    举个例子,多线程下载软件,可以同时运行多个线程,但是通过程序运行的结果发现,每一次结果都不一致。 因为多线程存在一个特性:随机性。造成的原因:CPU在瞬间不断切换去处理各个线程而导致的,可以理解成多个线程在抢CPU资源。

    多线程提高CPU使用率

    多线程

    多线程并不能提高运行速度,但可以提高运行效率,让CPU的使用率更高。但是如果多线程有安全问题或出现频繁的上下文切换时,运算速度可能反而更低。

    Java中的多线程

    Java程序的进程里有几个线程:主线程,垃圾回收线程(后台线程)等

    在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程。

    Java支持多线程,当Java程序执行main方法的时候,就是在执行一个名字叫做main的线程,可以在main方法执行时,开启多个线程A,B,C,多个线程 main,A,B,C同时执行,相互抢夺CPU,Thread类是java.lang包下的一个常用类,每一个Thread类的对象,就代表一个处于某种状态的线程

    展开全文
  • 有一次面试的时候,被问到进程之间有哪些通信方式,不过由于之前没深入思考且整理过,说的并不好。想必大家也都知道进程有哪些通信方式,可是我猜很多人都是靠着”背“来记忆的,所以今天的这篇文章,讲给大家详细着...

    有一次面试的时候,被问到进程之间有哪些通信方式,不过由于之前没深入思考且整理过,说的并不好。想必大家也都知道进程有哪些通信方式,可是我猜很多人都是靠着”背“来记忆的,所以今天的这篇文章,讲给大家详细着讲解他们是如何通信的,让大家尽量能够理解他们之间的区别、优缺点等,这样的话,以后面试官让你举例子,你也能够顺手拈来。

    1、管道

    我们来看一条 Linux 的语句

    netstat -tulnp | grep 8080
    

    学过 Linux 命名的估计都懂这条语句的含义,其中”|“是管道的意思,它的作用就是把前一条命令的输出作为后一条命令的输入。在这里就是把 netstat -tulnp 的输出结果作为 grep 8080 这条命令的输入。如果两个进程要进行通信的话,就可以用这种管道来进行通信了,并且我们可以知道这条竖线是没有名字的,所以我们把这种通信方式称之为匿名管道

    并且这种通信方式是单向的,只能把第一个命令的输出作为第二个命令的输入,如果进程之间想要互相通信的话,那么需要创建两个管道。

    居然有匿名管道,那也意味着有命名管道,下面我们来创建一个命名管道。

    mkfifo  test
    
    

    这条命令创建了一个名字为 test 的命名管道。

    接下来我们用一个进程向这个管道里面写数据,然后有另外一个进程把里面的数据读出来。

    echo "this is a pipe" > test   // 写数据
    

    这个时候管道的内容没有被读出的话,那么这个命令就会一直停在这里,只有当另外一个进程把 test 里面的内容读出来的时候这条命令才会结束。接下来我们用另外一个进程来读取

    cat < test  // 读数据
    

    我们可以看到,test 里面的数据被读取出来了。上一条命令也执行结束了。

    从上面的例子可以看出,管道的通知机制类似于缓存,就像一个进程把数据放在某个缓存区域,然后等着另外一个进程去拿,并且是管道是单向传输的。

    这种通信方式有什么缺点呢?显然,这种通信方式效率低下,你看,a 进程给 b 进程传输数据,只能等待 b 进程取了数据之后 a 进程才能返回。

    所以管道不适合频繁通信的进程。当然,他也有它的优点,例如比较简单,能够保证我们的数据已经真的被其他进程拿走了。我们平时用 Linux 的时候,也算是经常用。

    2、消息队列

    那我们能不能把进程的数据放在某个内存之后就马上让进程返回呢?无需等待其他进程来取就返回呢?

    答是可以的,我们可以用消息队列的通信模式来解决这个问题,例如 a 进程要给 b 进程发送消息,只需要把消息放在对应的消息队列里就行了,b 进程需要的时候再去对应的
    消息队列里取出来。同理,b 进程要个 a 进程发送消息也是一样。这种通信方式也类似于缓存吧。

    这种通信方式有缺点吗?答是有的,如果 a 进程发送的数据占的内存比较大,并且两个进程之间的通信特别频繁的话,消息队列模型就不大适合了。因为 a 发送的数据很大的话,意味**发送消息(拷贝)**这个过程需要花很多时间来读内存。

    哪有没有什么解决方案呢?答是有的,请继续往下看。

    3、共享内存

    共享内存这个通信方式就可以很好着解决拷贝所消耗的时间了。

    这个可能有人会问了,每个进程不是有自己的独立内存吗?两个进程怎么就可以共享一块内存了?

    我们都知道,系统加载一个进程的时候,分配给进程的内存并不是实际物理内存,而是虚拟内存空间。那么我们可以让两个进程各自拿出一块虚拟地址空间来,然后映射到相同的物理内存中,这样,两个进程虽然有着独立的虚拟内存空间,但有一部分却是映射到相同的物理内存,这就完成了内存共享机制了。

    4、信号量

    共享内存最大的问题是什么?没错,就是多进程竞争内存的问题,就像类似于我们平时说的线程安全问题。如何解决这个问题?这个时候我们的信号量就上场了。

    信号量的本质就是一个计数器,用来实现进程之间的互斥与同步。例如信号量的初始值是 1,然后 a 进程来访问内存1的时候,我们就把信号量的值设为 0,然后进程b 也要来访问内存1的时候,看到信号量的值为 0 就知道已经有进程在访问内存1了,这个时候进程 b 就会访问不了内存1。所以说,信号量也是进程之间的一种通信方式。

    5、Socket

    上面我们说的共享内存、管道、信号量、消息队列,他们都是多个进程在一台主机之间的通信,那两个相隔几千里的进程能够进行通信吗?

    答是必须的,这个时候 Socket 这家伙就派上用场了,例如我们平时通过浏览器发起一个 http 请求,然后服务器给你返回对应的数据,这种就是采用 Socket 的通信方式了。

    总结

    所以,进程之间的通信方式有:

    1、管道

    2、消息队列

    3、共享内存

    4、信号量

    5、Socket

    讲到这里也就完结了,之前我看进程之间的通信方式的时候,也算是死记硬背,并没有去理解他们之间的关系,优缺点,为什么会有这种通信方式。所以最近花点时间去研究了一下,
    整理了这篇文章,相信看完这篇文章,你就可以更好着理解各种通信方式的由来的。

    唠叨一下,最近有点对不住各位,好久没写原创文章了。有点偷懒,哈哈。不过呢,我接下来会好好写文章的了,希望大家多多支持。

    老铁,要不点个赞再走可好?么么哒

    1、给俺点个赞呗,可以让更多的人看到这篇文章,顺便激励下我,嘻嘻。

    2、老铁们,关注我的原创微信公众号「帅地玩编程」,专注于写算法 + 计算机基础知识(计算机网络+ 操作系统+数据库+Linux)。

    保存让你看完有所收获,不信你打我。后台回复『电子书』送你一份精选电子书大礼包,包含各类技能的优质电子书。

    作者简洁

    作者:大家好,我是帅地,从大学、校招一路走来,深知算法计算机基础知识的重要性,所以申请了一个微星公众号『帅地玩编程』,专业于写这些底层知识,提升我们的内功,帅地期待你的关注,和我一起学习。 转载说明:未获得授权,禁止转载了。

    展开全文
  • 查看Linux端口占用,并kill掉相关进程

    万次阅读 多人点赞 2018-06-13 16:57:49
    话不多说,本文介绍Linux常规操作:查看端口占用进程,根据PID kill掉相关进程。另外补充:根据程序名查看进程PID。 首先,两条命令,lsof命令和netstat命令。 方式一:lsof命令 1、查看占用端口进程的PID: ...
  • Linux中查看进程状态信息

    万次阅读 2018-10-24 22:00:21
    Linux中查看进程状态信息 一、常用命令总结 ps -l 列出与本次登录有关的进程信息; ps -aux 查询内存中进程信息; ps -aux | grep *** 查询***进程的详细信息; top 查看内存...
  • Linux系统编程——特殊进程之守护进程

    万次阅读 多人点赞 2015-05-25 19:02:32
    守护进程是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。由于在 Linux 中,每一个系统与...
  • Linux查看进程命令

    万次阅读 多人点赞 2019-04-21 15:12:57
    -ef,以全格式显示进程所有信息,包括父进程Pid,创建人,创建时间,进程号。等等 一般项目中,我们首先要查询一个进程,并对其进行删除会用一下命令 ps -a | grep helloworld 或 ps -ef |grep helloworld 或者...
  • linux进程隐藏与对抗

    万次阅读 2020-11-12 11:34:44
    以及/proc/进程pid/cmdline文件开始获取进程信息 (4)然后打印输出 攻击者可以劫持getdents和libc中的readdir函数(修改内核中的系统调用代码或者修改lib中的函数代码)实现过滤特定进程名,从而实现进程隐藏。...
  • 进程和线程的主要区别(总结)

    万次阅读 多人点赞 2018-06-13 10:11:52
    根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类...
  • Windows进程

    万次阅读 2020-06-23 21:46:48
    进程的创建 BOOL CreateProcess( LPCTSTR lpApplicationName, // name of executable module LPTSTR lpCommandLine, // command line string 命令行参数 LPSECURITY_ATTRIBUTES ...
  • 急!CPU 被挖矿了,却找不到哪个进程

    万次阅读 多人点赞 2021-01-15 18:42:40
    通过排查挖矿病毒的一次“有趣”经历,本文不仅展示了各种 Shell 命令的用法和作用,也能加深读者对Linux 进程和文件系统的理解。 同时在本文中,还出现了各种不同的工具类网站,相信对于一些专业人士会很有帮助。 ...
  • Linux下查询端口占用的进程

    万次阅读 2017-10-18 10:05:49
    查询端口占用的进程 1.查询进程 netstat -tunlp|grep 端口号 此时可查出进程的PID 2.查询相应进程 ps -ef | grep 进程
  • 在Android系统中,每一个应用程序都是由一些Activity和Service组成的,这些Activity和Service有可能运行在同一个进程中,也有可能运行在不同的进程中。那么,不在同一个进程的Activity或者Service是如何通信的呢?这...
  • Android跨进程通信:图文详解 Binder机制 原理

    万次阅读 多人点赞 2017-06-22 10:31:24
    如果你接触过 跨进程通信 (IPC),那么你对Binder一定不陌生 虽然 网上有很多介绍 Binder的文章,可是存在一些问题:浅显的讨论Binder机制 或 一味讲解 Binder源码、逻辑不清楚,最终导致的是读者们还是无法形成一...
  • Linux查看进程,关闭进程

    万次阅读 2019-06-09 19:54:32
    ps -aux //完整的显示当前用户的所有进程 ps -ef|grep <进程名> //查看并筛选 跟进程名有关的进程,该进程名可以是进程的全部或者部分。 kil -9 pid //关闭进程 ...
  • 进程-进程标识符

    千次阅读 2017-05-17 19:15:02
    1.什么是进程标识符 系统给每个进程定义了一个唯一标识该进程的非负正数,称作进程标识符。当某一进程终止后,其标识符可以重新用作另一进程的标识符。不过,在任何时刻,一个标识符所代表的进程是唯一的。系统把...
  • 进程 第二天 (fork函数&子进程与父进程&守护进程)

    万次阅读 多人点赞 2018-08-13 20:37:20
    详细标注:进程 第二天 (fork函数&amp;子进程与父进程&amp;守护进程) 一、fork()函数 在Linux系统内,创建子进程的方法是使用系统调用fork()函数。fork()函数是Linux系统内一个非常重要的函数,它与我们...
  • android查看当前手机中的进程

    万次阅读 多人点赞 2016-05-11 13:08:07
    正常情况下,每一个Android应用启动后都会对应一个进程,当前越来越多应用会有多个进程,为了推送,为了内存,或者为了保活。如何查看应用进程呢。1.DOS下面cmd,然后打开adb shell,直接ps命令,显示当前手机所有...
  • Linux系统根据进程号关闭后台进程

    万次阅读 2019-12-07 17:36:04
    查看后台所有端口的进程: netstat -nap 根据PID关闭进程: kill -9 PID PID是查到的进程号 现在再去查找所有进程 发现8080端口的进程已经被关闭了!
  • 写给大忙人看的进程和线程

    万次阅读 多人点赞 2020-03-03 15:44:21
    我们平常说的进程和线程更多的是基于编程语言的角度来说的,那么你真的了解什么是线程和进程吗?那么我们就从操作系统的角度来了解一下什么是进程和线程。 进程 操作系统中最核心的概念就是 进程进程是对正在运行...
  • Linux根据进程号查看进程位置

    万次阅读 2015-05-01 21:01:15
    Linux的所有进程都保存在/proc/目录下,保存形式为:/proc/进程号。进入到进程号目录后,里面有一个cwd链接文件即指向的进程的的目录。 2) 操作: A:确定进程号。如:4874; B:查找进程执行的文件。ps aux | grep...
  • 进程进程相互独立 (可以通过socket套接字实现进程间通信,可以通过硬盘(文件)实现进程通信,也可以通过队列(Queue)实现进程通信) 子进程会拷贝复制主进程中的所有资源(变量、函数定义等),所以子进程比子线程耗费...
  • 查看firefox的进程ID: ps -ef | grep firefox 或者 top | grep firefox   使用kill指令来终止进程: kill -s 9 进程ID // -s 9表示发送给进程的信号是9(SIGKILL);   根据进程的名字来终止进程: ...
  • 进程及多进程编程

    千次阅读 2018-08-17 15:05:56
    第一部分 进程知识总结  一、进程的定义 进程是执行中的程序,就类比于一出舞台剧的整个表演过程;进程动态性的实质是进程实体的执行过程;进程独立性是指每个进程都有自己的PCB;进程的并发性是内存中可以允许...
  • 前台进程  前台进程是Android系统中最重要的进程,是与用户正在交互的进程 可见进程 可见进程指部分程序界面能够被用户看见,却不在前台与用户交互。 服务进程  一个包含已启动服务的进程就是服务进程,...
  • 应用场景:后台图片备份,息屏计步 应用在深圳知名大型互联公司,日活用户2000万 支持系统2.3到6.0 支持大部分设备,包括三星,华为,oppo,nexus,...Android系统会在内存不足的时候去将进程杀死,俗称Low M...
  • 使用进程名获取进程id和进程句柄

    千次阅读 2018-05-04 22:18:06
    本文内容为编写一个任务管理器所需要的API介绍以及如何通过进程名称获取进程id的方法,函数使用频率高,所以贴出来以便复用。 相关api介绍 CreateToolhelp32Snapshot 函数功能为拍摄当前所有...
  • 进程是具有一定独立功能的程序关于一个数据集合的一次运行活动。进程具有以下主要特性: (1)并发性:可以与其它进程一道在宏观上同时向前推进。 (2)动态性:进程是执行中的程序。此外进程的动态性还体现在如下...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 689,847
精华内容 275,938
关键字:

进程