java线程和lwp是1比1吗_java高并发学习01——进程、线程、协程

1.进程、线程、协程

1.1进程

伪并行:在单处理器系统中,CPU由一个进程快速切换到另一个进程,使每个进程各运行几十或几百毫秒——严格来说,在某一个瞬间,CPU只能运行一个进程。但在1秒钟内,它可能运行了多个进程,这样就产生了并行的错觉,这种情形就被称为伪并行,以此来区分多出力系统的真正硬件并行。

1.1.1进程模型

在进程模型中,计算机上所有可运行的软件(包括操作系统),被组织成若干顺序进程,简称为进程。一个进程就是一个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。从概念上来说,每个进程都有自己的虚拟CPU,而实际上真正的CPU在进程之间来回切换,这种快速的切换被称作多道程序设计。

1.1.2进程生命周期

进程的创建:4种主要事件会导致进程的创建:

系统初始化。启动操作系统时,通常会创建若干个进程,包括前台进程和守护进程。

正在运行的程序执行了创建进程的系统调用,以便使新进程协助工作。

用户请求创建了一个新进程。

一个批处理作业的初始化。在操作系统认为有资源可以运行另一个任务时,它创建一个新的进程,并运行其输入队列中的下一个任务。

在Unix和Windows中,进程创建后,父进程和子进程有各自不同的地址空间。在Unix中,子进程的初始化地址空间是父进程的一个副本,但是它们的地址空间不同。其中不可写的内存是共享的。某些Unix的实现通过写时复制共享内存,即一旦两者之一要修改部分内存,则这块内存首先被复制。

进程的终止:通常由以下条件引起:

正常退出(自愿的)。

出错退出(自愿的)。

严重退出(非自愿的)。

被其它进程杀死(非自愿的)。

进程的状态:6f7ba93d04151d131b9cd7aaae55cd0f.png

1.1.3进程实现

为了实现进程模型,操作系统维护着进程表,每个进程占用一个进程表项。该表项包含了进程状态的信息,包括程序计数器、堆栈指针、内存分配状态、所打开的文件状态、账号和调度信息,以及其它在进程由运行态转换到就绪态时必须保存的信息,从而保证该进程随后能再次启动。7629a0202c72dc58e60cc64355d95c28.png

操作系统的中断是通过中断向量实现的,它包含中断服务程序的入口地址。当中断发生时,中断硬件会将当前程序计数器、程序状态字、一个或多个寄存器压入堆栈,计算机随即跳转到中断向量所指示的地址,然后就是软件接管剩下的工作。

软件从进程表项开始,删除堆栈中由中断硬件机制存入的信息,并将堆栈指针指向一个由进程处理程序所使用的临时堆栈,然后进行相关工作。当完成相关工作后就返回中断处继续执行原来的程序。

中断一般分为三类:

外中断:由CPU外部引起的,比如I/O中断、时钟中断。

内中断:来自CPU内部事件或程序执行中引起的中断,比如程序非法操作、地址越界、浮点溢出等。

最后一种是在程序中使用了系统调用,使得从用户态陷入到系统态引起的中断。

1.2线程

从 1.1.1进程模型 可知,进程是程序运行的实例,它维护着应用程序所需的各种资源(CPU时间片、内存等)。进程是资源分配的最小单位。

线程又被称为轻量级进程(Lightweight Process,LWP),是操作系统调度执行的最小单位。线程的引入使得进程模型可以通过同一个进程中并行运行多个线程模拟同一台计算机上并行运行多个线程,只不过前一种是多个线程共享一个地址空间和其它资源,后一种是多个进程共享物理内存。

1.2.1线程实现

在用户空间中实现线程:把整个线程包放在用户空间中,屏蔽内核包,从内核的角度来看还是进行单线程进行。

这样做的好处有:

用户级程序包可以在不支持线程的操作系统上实现。

线程切换快。

允许每个进程由自己的调度算法。

缺点:

线程发生由I/O或页面故障引起的阻塞时,如果调用阻塞系统则内核由于不知道有多线程的存在,而会阻塞整个进程从而阻塞所有线程。

如果一个线程开始允许,那么它所在的进程的其它线程就不能运行。

在内核中实现线程:内核中有用来记录系统中所有线程的线程表。当某个线程希望创建一个新线程或撤销一个已有线程时,它会进行系统级别的调用,这个系统调用通过对线程表的更新完成线程创建或撤销工作 。

优点:

所有能够阻塞线程的调用都以系统调用的形式实现。

如果某个线程引起了页面故障,内核可以很方便地检查该进程是否有任何其他可运行的线程。

混合实现:使用内核级线程,然后将用户级线程与某些或者全部内核线程多路复用。采用这种方法,内核只识别内核级线程,并对其进行调度。其中一些内核级线程会被多个用户级线程多路复用。

1.2.2进程通信

竞争条件:多个进程读取某些共享数据,最后的结果取决于进程运行的精确时序(竞争条件不是数据,而是一种情况)。

临界区:对共享内存访问的程序片段。如果能使进程间不会同时处于临界区,那么就能避免竞争条件。

进程间的通信方式:

管道(Pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系(父子进程关系)的进程间使用。

命名管道(FIFO):命名管道是半双工的通信方式,允许无亲缘关系进程间的通信。

消息队列(MessageQueue):消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

共享存储(SharedMemory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。

信号量(Semaphore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

套接字(Socket):套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

信号 ( Single ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

1.2.3进程调度

批处理系统的调度:

先来先服务。

最短作业优先。

最短剩余时间优先。

交互式系统的调度:

轮转调度。

优先级调度。

多级队列。

最短进程优先。

保证调度。

彩票调度。

公平分享调度。

实时系统的调度:实时系统可以分为硬实时(满足绝对的截止时间)和软实时(容忍偶尔的错失时间)。实时系统中的事件可以按照响应方式进一步划分为周期性和非周期性事件。一个系统可能要响应多个周期性事件流,如果所有周期事件的处理时间小于周期间隔,那么说明这个实时系统是可调度的。

实时系统的调度算法可以是静态或动态的。

1.3协程

1.3.1简述

从上面我们可以知道,进程是不执行任务的,执行任务的最小单元是线程,线程是轻量级的进程,而协程则是轻量级的线程。正如一个进程有一个或多个线程一样,一个线程有一个或多个协程,那么协程到底是什么,它的作用是什么呢?

前文我们说过,进程是属于内核的,线程即可以属于内核也可以属于用户,而协程是完全在用户态执行。协程实际上是一个特殊的函数,这个函数可以在某个地方挂起,并且可以在挂起处继续运行。协程是非抢占式的,因此需要用户自己释放使用权来切换到其它协程。

注意点:

协程的出现早于线程,它主要用于模拟多任务并发。

线程能利用多核达到真正的并行计算,而协程由于是非抢占式的,需要用户手动释放运行权,所以它实际上相当于单线程能力。

1.3.2有栈协程与无栈协程

协程分为有栈协程和无栈协程俩种. 区别在于是否有自己的调用栈来进行函数调用等操作。

有栈协程的实现:

采用操作系统提供的api 类似 ucontext 或者 setjump longjump

用汇编操控寄存器保存状态 典型的例子

无栈协程的实现:

栈帧内保存的不是状态而是指向状态的指针。

所有帧的状态保存在堆上。

无栈协程的效率要有栈协程要高,但是需要用户手动进行切换,实现细节过于复杂。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值