这篇文章的目的并非想教你如何造火箭(面试造火箭,工做拧螺丝),而是想经过对原理和应用案例的有限度剖析来协助你构建起并发的思惟,并将操做系统的理论知识与工程实践结合起来,贯穿从学到会的全过程。固然,虽然咱们是从实用角度出发,但具备实践意义的深层次知识点永远会是面试中的杀手锏,这可比只能口头造火箭的理论知识更吸引面试官。面试
本文适合谁:数据库
在这篇文章中,你将了解到并发与多线程相关的一系列概念,经过一些例子咱们能够在不纠结于具体的技术细节的状况下造成对并发与多线程相关的各类概念的抽象理解。有了这些概念之后,咱们再去学习具体的理论和技术细节就是手到擒来的事了。编程
最近几年淘宝发展得如火如荼,涌现出了一大批白手起家的卖家。想象一下你是一个刚刚起步的小卖家,本身运营一个服装网店,天天都要本身打包发货。刚开始时生意通常,天天本身一我的一个小时就能干完。网络
随着生意的蓬勃发展,发货时间慢慢地从一个小时涨到了两个小时、四个小时,一次由于延迟发货致使被投诉以后,你终于以为该招更多的人了。很快,两个小伙伴加入了你的事业,打包速度开始有了质的提升。这就是最基本的并发了,每一个人均可以当作是一个线程,一样的工做量,干得人多了天然就快了。多线程
因此并发
就是经过多个执行器同时执行一个大任务来缩短执行时间、提升执行效率的方法。并发
可是好景不长,周末一盘货,你发现少了很多。这办公室里也没遭贼,怎么就会少货呢?细细一查快递单,你发现居然有几单发重了。以后的几天你都细细留意了一下发货的过程,最后发现是由于每一个人都会拿着一张发货清单去备货,若是有一些订单不当心打印重复了,就有可能会被不一样的人重复发货。虽然数量很少,可是也很心痛啊。这个问题产生的缘由就是由于每一个人在备货以前拿到的订单状态(未发货)在实际备货时发生了变化(已由其余人发货)。这种对一个共享数据(订单的发货状态)本应独占的读取、检查、修改过程,若是发生了并发,这种状况就被称为数据竞争
。而这个读取、检查、修改的过程就被称为临界区
,临界区
指的就是一个存在数据竞争
的代码片断。分布式
数据竞争出现的根本缘由是一个数据原本应该只能由一个执行器完整地执行读取、检查、修改过程,可是若是出现了并发,那么就没办法保证到了“修改”这一步时的数据还保持了“读取”时的值了。工具
肯定缘由后,有人想到了一个好办法,能够打印一张总的发货清单,这样全部人都必须以这个清单上的订单是否发货来肯定是否要对订单进行备货并发货了。由于清单只有一份,因此每次只能由一我的来修改订单的发货状态。这种只能由一个执行器进行数据修改操做来避免发生数据竞争
问题的作法就被称为互斥
,也就是咱们常说的锁
了。oop
由于你管理得当,生意发展得很快,如今的办公室里已经堆不下全部衣服了。因此你又租了一个仓库来一样进行发货。两个地方都会进行发货,那么就能够把每个仓库理解为一台独立的计算机,这样经过多台计算机完成同一任务的方式就能够被称为分布式
,这样的一组计算机的集合就被称为集群
。post
这时候以前用一张纸质的总发货清单的数据竞争
解决方式就行不通了,因此咱们须要把这张总发货清单放到云端,让你们能够经过网络进行编辑,可是每次只能一我的编辑。在这种状况下,咱们能够把两个仓库各自当作一台计算机/进程,而每一个仓库里的人就是这个进程中的线程。这样的话这张总发货清单就成为了一个分布式锁
,由于它每次只能有一我的编辑,因此是一个互斥锁
,或者简称为锁
;而由于它能够被两个进程/计算机(仓库)共同使用,因此被称为是分布式锁
。
什么是进程/线程?
能够简单地将进程理解为咱们电脑/手机上的一个应用,同一台手机上的每一个App都是一个进程,同一个App在每一个手机上也是一个进程。进程和进程之间能够理解为是两个仓库,互相之间物理隔离;而线程就是仓库里的每个人,他们共享同一个办公空间。这里的办公空间就能够理解为操做系统中的虚拟内存空间,可是本文主要讨论并发相关的概念,就不继续展开了。
由于生意比较好,因此全部人都很忙。有时候就会由于有一些人虽然在云端表格上已经勾上了一个订单,可是一忙就给忙忘了。其余人怕重复发货又不会再去处理已经勾上的订单了,由于这样致使的未发货订单让店铺被投诉了好屡次,影响很是大。这种在并发过程当中修改了数据状态可是没有完成后续执行的状况就会出现数据不一致
,即订单已经被勾上,但实际并无发货。
可是做为聪明的老板,你又想到了解决的方法。每隔一小时两个仓库就会各派一我的检查一下已经勾上的订单是否已经都打包完贴上快递单了。这种每隔一段时间就检查并处理遗漏的数据不一致
订单的任务就被称为兜底任务
。而经过兜底任务
实现的在最后全部订单都会达到数据一致状态的状况就被称为最终一致性
。
你们可能早就以为前面介绍的总发货清单的方法太傻了,只要每一个订单都只打印一张发货清单,由单独一我的去负责分发清单就能够了,其余人只要处理好本身被分配到的订单就能够了。最后再加上一个兜底任务对订单的发货状况进行二次校验基本上就不会发生漏发或者重发的状况了。这种由一个执行器进行任务拆分,再由一组执行器进行处理,最后再由一个或一组执行器进行结果汇总的处理方式就是如今很是流行的map-reduce
方法了。这种方法在大数据或者程序语言标准库里都有大量的应用,好比大数据领域赫赫有名的Hadoop和Java语言中的ForkJoinPool
都使用了这种思想。
在这篇文章中,咱们涉及到了如下的技术名词:
数据竞争
的代码片断。数据不一致
状态的任务。兜底任务
或其余方式保证数据不一致
的状况最终会消失。由于并发的知识范围很大,并且对于一些抽象概念的传递必然会须要花费一些篇幅,因此这个主题将会包含一系列文章,主要覆盖如下主题:
有兴趣的读者能够继续关注后续的文章,在以后的文章中会有对并发编程、操做系统原语、硬件原语等等理论与实践知识的详细介绍与案例。
对数据库索引感兴趣的读者能够了解一下我以前的文章: