最近遇到了一个和多线程有关的事,顺便简单复习了下相关概念,稍后举个栗子🌰来解释下。
进程 and 线程
进程我们都知道,就是应用程序的启动实例。比如我们运行一个游戏,打开一个软件,就是开启了一个进程。
而线程从属于进程,是程序的实际执行者。一个进程至少包含一个主线程,也可以有更多的子线程。
我们可以简单的理解:为了做一件事,我开了一个进程,为了让这件事更有效率的完成,我开了多个线程。
### 从找对象入手加深理解
如果这么说还是不清楚的话,我们以一个找对象的例子来加深理解:
读研了,望着身边的小伙伴一个个都是成双成对,笔者有一个万年单身的好基友就跟一条酸菜鱼似的(又酸又菜又多余),想着要不也找个女朋友吧?于是就创建了一个名为 「找对象」的进程。但是学校女生太多了,如果一个一个试的话不知道啥时候才能脱单。这时候,万能的度娘给出了建议,为什么不同时下手呢?
于是,他就创建了两个「撩妹」的线程,每个线程负责撩一个妹子。但这时就有问题出来了。
虽然他可以同时撩两个妹子,但是有些事情就是没办法同时和两个妹子做,比如上课、吃饭、散步。这个时候就需要 「数据保护」。做这些事情的时候,他一次只能跟一个妹子做,这就叫做 「临界区」。他撩的两个妹子,一个是红玫瑰,一个是白玫瑰,各有各的特点,这是她们的 「私有属性」。这两个妹子都可以跟他约会,此时他就是一个 「共享内存」。如果某一天他跟其中一个妹子在外面约会,那另一个撩妹线程就只能 「阻塞」 了。但是为了防止后院起火,不让另一个妹子不爽,他就只能发条朋友圈说自己在学习,不想被打扰,这就叫 「互斥锁」。同时为了不让她们影响对方的存在,他用QQ叫着其中一个的小名,微信却是另一个的情侣头像,这就是「消息传递」。
上述两个线程在某种意义上就构成了 「竞态条件」(个人认为叫做「竞争状态」会更好)。如果他只有这两个线程的话,想要完成「找对象」这个进程,就只能看这两个线程谁的执行效率更高(其实就是看谁先运行完) 了。这么一看,我的好基友貌似很快就可以完成「找对象」这一进程了,因为无论是哪个线程,只要有一个「撩妹」线程结束了,整个进程也就结束了。
但是在结束前可能会出现一些问题(注意这里是可能),如果他在排约会档期时一旦没有进行良好的调度,就很有可能会出现两个妹子约在同一天约会,基友却没办法到达的情况,这种情况就叫 「死锁」,即较长时间的等待或资源竞争。亦或是如果不幸被两个妹子都发觉了对方的存在,却又为表大度,你让我我让你,最终导致「找对象」进程无法进行下去,这就叫做 「活锁」。 如果此时出现了一个 「工具人」 妹子,主动倒追我基友,这样的话即使被加入了「找对象」的进程,也可能会因为一系列问题始终没法和他单独约会(毕竟还有两个「撩妹」线程在进行着),这种情况就叫做 「饥饿」。 这三种情况总结一下就是:
- 死锁:争来争去 谁也得不到
- 活锁:让来让去 谁都不拥有
- 饥饿:排多久 都轮不到自己
倘若我基友最后撩成功的女朋友并不是他最喜欢的那个人,即最终的运行结果和预期不同,这就叫 「线程不安全」。反之,如果最后撩成功的妹子是他最喜欢的,即最终的结果和预期相同,那这个就叫 「线程安全」。
这么一看,真是人生如戏。只是可悲的是,我本以为现在执行的是一个单进程,却没想到也只是别人的一个线程罢了。