您的位置:首页 > 其它

《并发 系列》- 并发中的几个概念

2017-12-25 00:00 351 查看

前言

本文主要介绍并发中的几个概念知识。

同步和异步

同步和异步关注的是消息通信机制((synchronous communication/ asynchronous communication))。

同步:发出一个调用,在没有得到结果前,该调用不返回。一旦调用返回,结果也返回。

你打电话问书店老板有XX书没,书店老板说你稍等。书店老板什么时候查到就什么时候告诉你结果。

异步:发出一个调用,不管有没结果,该调用都直接返回。被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。

你打电话问书店老板有XX书没,书店老板告诉你查好了打电话回你,然后直接挂电话。查好了,书店老板通过“回电”这种方式来告诉你。

并发和并行

并发(Concurrency) 是在 某一时段内 有多个任务在执行;

并行(Parallelism) 是在 某一时刻上 有多个任务在执行。



并发是两个队列交替使用一台咖啡机,并行是两个队列同时使用两台咖啡机。

并发和并行都可以是多线程,如果这些线程能同时被(多个)CPU执行执行,就说明是并行;而并发是多个线程被(一个)CPU轮流切换着执行。

临界区

每个线程中访问临界资源的那段代码称为临界区(Critical Section)(临界资源是一次仅允许一个线程使用的共享资源)。

阻塞和非阻塞

阻塞(Blocking)和非阻塞(Non-Blocking)关注的是程序在等待调用结果(消息,返回值)时的状态。

阻塞:调用结果返回前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。

你打电话问书店老板有XX书没,你会一直在话机前等待(把自己“挂起”),直到老板告诉你结果。

非阻塞:在不能立刻得到结果之前,该调用不会阻塞当前线程。

你打电话问书店老板有XX书没,然后你自己去干其他事情了,然后隔几分钟check一下老板有没有结果

死锁、饥饿和活锁

死锁(Deadlock):几个线程占用所有的资源而不释放资源,那么其他线程就不能获得该资源,且这种情况会一直持续下去。

静态的,CPU使用率为0

饥饿(Starvation):线程因为种种原因无法获得所需要的资源,导致一直无法执行下去。

在争夺资源的时候可能优先级低的线程一直抢不到资源导致处于饥饿的状态。

饥饿相比死锁的那种情况还是好点,至少在未来的一段时间还能解决的。

活锁(Livelock):一个线程获得了资源后,发现另一个资源无法拿到,为了避免死锁,就把已经占有的资源全部弃掉。另一个线程也做同样的事。不断的抢资源、释放资源,导致一个线程不能拿到所有的资源,而不能正常执行下去。

动态的,CPU达到100%

并行的级别

阻塞

一个线程进入临界区之后,其他线程必须在临界区外等待。

当线程处于阻塞的时候,该线程就相当于暂停状态。

阻塞调度是一种悲观的策略,多个线程操作临界区会把数据改坏。每次只能一个线程进入临界区。

使用synchronized关键字的时候或者我们使用重入锁的时候会出现阻塞的情况。

无障碍(非阻塞)

无障碍是一种最弱的非阻塞调度。多个线程可自由进入临界区。不会因为临界问题导致一方线程处于挂起状态,如果遇到共享的数据出现问题,会自动的进行数据回滚,确保数据的安全。这是一种乐观的调度。

在非阻塞调度上必须至少保证一个线程能够完成操作。创建一个标记来实现,在操作前 读取这个标记,在操作完成后再读取该标记查看该标记是否被更改过。两次都是一致的那么资源没有冲突,如果不一致,与其他线程有冲突,就需要进行进行数据回滚。

可能出现进入临界区的线程相互影响,都无法执行。

无锁(非阻塞)

无锁首先是无障碍,所有线程都能进入临界区。

无锁情况下并发保证必然有一个线程能够在有限步内完成操作。

该操作的一个典型特点是 可能包含了一个无穷循环。循环中线程会不断的尝试修改共享变量,在没有冲突的情况下会修改成功,程序执行完毕,否则会继续尝试修改。这是一个碰运气的情况,总会有一个尝试成功。

无等待(非阻塞)

无等待首先是无锁的,要求所有的线程必须在有限的步内完成,这样就不会造成饥饿的状态。

如果对步骤进行限制还可以分为 有界无等待,和线程数无关的无等待集中。区别就是 循环次数不同而已。

举例说明无等待的结构就是RCE ,读线程 不需要等待。写数据时先得到数据的副本 就是copy一下,然后修改完成后再在某个时候完成对原数据的修改
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  并发