什么是并发

04月18日 收藏 0 评论 2 java开发

什么是并发

转载声明:文章来源https://blog.csdn.net/Bonie_juzi/article/details/83412185?

一、为什么要学习并发:

充分利用CPU资源,帮助我们编写出高性能的程序。
ps:如果视而不见(并发问题),终将遭其反噬。

二、并发的特点:

1、速度(更快的执行):

通常,并发都是提高运行在单处理器上的程序性能;(事实上,如果没有阻塞。那么在单处理器上的使用并发毫无意义。)

2、设计可管理(改进代码的设计):

java线程机制都是抢占式的,即调度机制会周期性的中断线程,将上下文切换到另一个线程,从而为每个线程都提供时间片,使得每个线程都会分配到数量合理的时间去驱动他的任务。
协作多线程:每个任务都会自动放弃控制,由程序员有意识的插入让步语句;
协作的优势:上下文切换的开销比抢占式要小很多。

3、基本的线程机制:

并发编程将程序分为多个分离的、独立运行的任务;通过使用多线程机制,这些独立任务每一个都将由执行线程来驱动
(一个线程就是在进程中一个单一的顺序控制流)。每个任务(线程)都会“认为”自己一直占用CPU,但事实上CPU时间是划分成片段分配给了所有任务。

三、多线程的缺点:

1.设计更加复杂

2.上下文切换的开销:当CPU从执行一个线程切换到另一个时,它需要先存储当前线程的本地数据、程序指针等,然后载入另一个线程的本地数据、程序指针等,最后才开始执行。这种切换称为“上下文切换”;

3.增加资源消耗:线程在运行时除了使用CPU,还需要一些内存来维持他本地的堆栈,也需要占用操作系统中一些资源来管理线程。

四、并发编程模型

并发系统可以采用多种并发模型来实现。并发模型指定了系统中的线程如何通过写作来完成分配给他们的作业。

4.1并行工作者(最常见的并发模型)

工作原理图 

工作原理图(访问共享数据)

在并行工作者模型中,委派者(Delegator)将传入的作业分配给不同的工作者。每个工作者运行在不同的线程上,甚至不同的CPU上。

如果在某个汽车厂里实现了并行工作者模型,每台车都会由一个工人来生产。工人们将拿到汽车的生产规格,并且从头到尾负责所有工作

优点:易理解。提高系统的并行度只需要添加更多worker。

缺点
共享状态可能很复杂。当涉及到对共享数据的操作时,情况就变得复杂起来了。当某一个线程对共享数据进行存取操作时,也要确保被其他线程可见。线程需要避免竟态,死锁以及很多其他共享状态的并发性问题。此外,在执行需要访问共享数据结构部分的代码时,高竞争基本上会导致执行时出现一定程度的串行化,线程之间的互相等待将会丢失部分并行性。现在的非阻塞并发算法、可持久化的数据结构等都可以在一定程度上解决部分问题,但并不理想。

无状态的工作者。共享状态能够被系统中得其他线程修改。所以工作者在每次需要的时候必须重读状态,以确保每次都能访问到最新的副本,不管共享状态是保存在内存中的还是在外部数据库中。工作者无法在内部保存这个状态(但是每次需要的时候可以重读)称为无状态的。每次都重读需要的数据,将会导致速度变慢,特别是状态保存在外部数据库中的时候。

任务顺序不确定。 另一个缺点就是作业执行顺序不确定。无法保证哪个作业最先或者最后被执行。

4.2流水线模型(反应器系统、事件驱动系统)

类似工厂生产线上工人一般,每个工作者只负责作业中的部分工作,当完成了自己这部分工作时就会把作业转发给下一个工作者,每个工作者都只在自己的线程中运行,并不会和其他工作者共享状态。

实际应用中可能的情况:



多个不同的虚拟流水线同时运行 

作业被转发到超过一个工作者上并发处理

采用流水线并发模型的系统有时候也称为反应器系统或事件驱动系统。系统内的工作者对系统内出现的事件做出反应,这些事件也有可能来自于外部世界或者发自其他工作者。事件可以是传入的HTTP请求,也可以是某个文件成功加载到内存中等。

比较流行的反应器/事件驱动平台:
Vert.x
AKKa
Node.JS(JavaScript)

4.3Actors 和 Channels

Actors 和 channels 是两种比较类似的流水线(或反应器/事件驱动)模型。


在Actor模型中每个工作者被称为actor。Actor之间可以直接异步地发送和处理消息。Actor可以被用来实现一个或多个像前文描述的那样的作业处理流水线。

而在Channel模型中,工作者之间不直接进行通信。相反,它们在不同的通道中发布自己的消息(事件)。其他工作者们可以在这些通道上监听消息,发送者无需知道谁在监听。

优点

①无需共享的状态。这意味着实现的时候无需考虑所有因并发访问共享对象而实现的并发性问题。在实现工作者时就好像单线程在处理工作。

②有状态的工作者。当工作者知道了没有其他线程可以修改它们的数据,工作者可以变成有状态的。对于有状态,我是指,它们可以在内存中保存它们需要操作的数据,只需在最后将更改写回到外部存储系统。因此,有状态的工作者通常比无状态的工作者具有更高的性能。

③较好的硬件整合。单线程代码在整合底层硬件时具有更好的优势。原因有二:第一,单线程代码通常能创建更优化的数据结构和算法。第二,单线程有状态的工作和能够在内存中缓存数据。也就意味着很有可能也缓存在执行这个线程的CPU的缓存中,这使得访问缓存的数据变得更快。

④合理的作业顺序。基于流水线并发模型实现的并发系统,在某种程度上是有可能保证作业的顺序的。这样就更容易推出系统某个特定时间点的状态,更进一步,你可以将所有到达的作业写入日志中。一旦系统某部分出现问题,该日志就可以用来重建系统。

缺点:流水线并发模型最大的缺点是作业的执行往往分布到多个工作者上,并因此分布到项目中的多个类上。这样导致在追踪某个作业到底被什么代码执行时变得困难。同样,这也加大了代码编写的难度。有时会将工作者的代码写成回调处理的形式。若在代码中嵌入过多的回调处理,往往会出现所谓的回调地狱(callback hell)现象。

4.3函数式并行(Functional Parallelism)

函数式并行的基本思想是采用函数调用实现程序。函数可以看作是”代理人(agents)“或者”actor“,函数之间可以像流水线模型(AKA 反应器或者事件驱动系统)那样互相发送消息。某个函数调用另一个函数,这个过程类似于消息发送。

函数都是通过拷贝来传递参数的,所以除了接收函数外没有实体可以操作数据。这对于避免共享数据的竞态来说是很有必要的。同样也使得函数的执行类似于原子操作。每个函数调用的执行独立于任何其他函数的调用。

一旦每个函数调用都可以独立的执行,它们就可以分散在不同的CPU上执行了。这也就意味着能够在多处理器上并行的执行使用函数式实现的算法。


C 2条回复 评论
运输大队长

大厂面试的时候看重基础,更看重实战项目经验,业务场景使用的具体技术吧

发表于 2023-02-17 22:00:00
0 0
信长之野望

我是大学学的Java开发、现在转行做了测试刚做两个多月

发表于 2022-12-17 22:00:00
0 0