同步和异步
同步就好比打电话,通信双方,你一句我一句,一句话得不到回应就会一直问:“喂?喂?可以听到么?是不是信号不好呀”。
异步就像发短信,发完短信我就去干点别的,看个视频、玩个游戏、干啥都行,等对方给我回信息了我再来处理短信(也可以不处理)。
线程和进程
进程的概念听起来很抽象,不大好理解。但是我知道你肯定认识这个东西,请看下图:
上方这些占用我的电脑CPU、内存、磁盘、网络的这些就都是进程。
那什么是线程呢?线程可以理解成是在进程中独立运行的子任务。比如微信运行时就会有很多的子任务在同时运行。比如,视频线程、下载线程、表情线程、语言线程等。简单来说,一组线程互相协作完成某一个程序的一些功能供我们使用。
并发和并行
- 并发和并行乍一看好像是一种东西,但是实际上区别很大。并发表示的是交替做不同事情的能力,而并行表示的是同时做不同事情的能力。例如你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这就是并发。你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这是并行。
- 我们常说的高并发系统就是说的并发而不是并行。
- 并不是所有的系统都可以实现并行,因为一个CPU一次只能执行一条指令,所以想要实现并行必须是多核才可以
临界资源
临界资源:是一次仅允许一个进程使用的共享资源。例如公共电话,一次只能一个人使用
临界区:每个进程中访问临界资源的那段代码叫做临界区。例如使用公共电话的人
阻塞
线程在试图执行代码前,会试图获取临界区的锁,如果得不到,线程就会被挂起等待,从而形成阻塞。
死锁
多个线程循环等待它方占有的资源而无限期地僵持下去的局面。例如两个人想要使用公共电话打电话,结果一个人抢到了话筒,一个人拨了号。两个人谁也不让谁,就会无休止地等下去从而引起死锁。
死锁产生的四大必要因素:
- 互斥:某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。
- 占有且等待:一个进程本身占有部分资源,同时还有资源未得到满足,正在等待其他进程释放该资源。
- 不可抢占:别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。
- 循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源。
当以上四个条件都满足时才会发生死锁,所以想要避免死锁只要能破坏上方四个条件的任意一个都可以。
饥饿
线程因为优先级或其他原因始终无法获取到临界资源。例如A在使用公用电话在打电话,B来了之后在后面排队。之后C来了,一看认识A,好么,哥们你打完我来。然后D来了,他认识C。。。就这样B一直等待从而引起饥饿。
活锁
多个相互协作的线程为了彼此间的响应而相互礼让,使得没有一个线程能够继续前进,那么就发生了活锁。例如两个人在一个很宅的胡同里。一次只能并排过两个人。两人比较礼貌,都要给对方让路。 结果一起要么让到左边,要么让到右边,结果仍然是谁也过不去从而引起的活锁。
线程的并发级别
-
1. 阻塞:参见上方阻塞的定义
-
2. 无饥饿:对比上方的饥饿,如果设置所有线程的优先级相同,则任何想要获取资源的线程都要排队,那么所有的线程都有机会执行。
-
3. 无阻塞:所有线程一起修改临界资源,修改完成后读取该资源是否被其他线程修改,如被其他线程修改则进行回滚,然后进行重试。
-
4. 无锁:前面说的无阻塞是指所有的线程都能进入临界区,但如果发生了竞争,线程发现自己的数据每次去操作总是跟其它线程产生冲突,它就会不停地重试,如果在临界区当中有10个线程,线程1修改了部分数据,结果它被线程2干扰了,线程2又被线程3干扰,依此类推,最后线程1它又可能去干扰线程10,如果它们之间是彼此干扰的,最终会导致所有的线程都卡死在里面。而无锁在无阻塞的基础上加一个了约束,保证在竞争当中有一个线程是必然能够胜出的,这样就能保证在临界区的线程当中至少有一个是能顺利走出去的。当第一个线程走出去之后,就有第二个线程、第三个线程、等所有的线程都能走出去
-
5. 无等待:无等待相比于无锁更进一步,它保证所有线程能进并且至少有一个线程能出来的同时还要求所有进入临界区的线程都能够在有限步当中完成其操作。
喜欢这篇文章的朋友可以点个喜欢,也可以关注一下我的个人专题:Java成长之路
针对于上面所涉及到的知识点我总结出了有1到5年开发经验的程序员在面试中涉及到的绝大部分架构面试题及答案做成了文档和架构视频资料免费分享给大家(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术资料),希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习,也可以关注我一下以后会有更多干货分享。
网友评论